Merge branch 'testing-leak-detective'

Test scenarios now fail if any leaks are detected by the leak detective.
Several leaks found this way have been fixed.
This commit is contained in:
Tobias Brunner 2016-09-20 16:26:58 +02:00
commit f654324e5e
16 changed files with 179 additions and 75 deletions

View File

@ -9,7 +9,8 @@ project Build_Common is
C_Compiler_Switches := ("-W",
"-Wall",
"-Wno-unused-parameter");
"-Wno-unused-parameter",
"-g");
Ada_Compiler_Switches := ("-gnatwale",
"-gnatygAdISuxo",
"-gnata",

View File

@ -373,6 +373,7 @@ int main(int argc, char *argv[])
run();
unlink_pidfile();
free(pidfile_name);
status = 0;
charon->bus->remove_listener(charon->bus, &listener->listener);
listener->destroy(listener);
@ -382,7 +383,7 @@ int main(int argc, char *argv[])
deinit:
destroy_dh_mapping();
libcharon_deinit();
library_deinit();
tkm_deinit();
library_deinit();
return status;
}

View File

@ -70,6 +70,8 @@ typedef struct {
enumerator_t *inner;
/** response of the DNS resolver which contains the CERTs */
resolver_response_t *response;
/** most recently enumerated certificate */
certificate_t *cert;
} cert_enumerator_t;
METHOD(enumerator_t, cert_enumerator_enumerate, bool,
@ -101,17 +103,17 @@ METHOD(enumerator_t, cert_enumerator_enumerate, bool,
/* Try to parse PEM certificate container. Both x509 and PGP should
* presumably come as PEM encoded certs. */
certificate = cur_crt->get_certificate(cur_crt);
*cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_ANY,
BUILD_BLOB_PEM, certificate,
BUILD_END);
if (*cert == NULL)
DESTROY_IF(this->cert);
this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_ANY,
BUILD_BLOB_PEM, certificate,
BUILD_END);
cur_crt->destroy(cur_crt);
if (!this->cert)
{
DBG1(DBG_CFG, " unable to parse certificate, skipping",
cur_crt->get_cert_type(cur_crt));
cur_crt->destroy(cur_crt);
DBG1(DBG_CFG, " unable to parse certificate, skipping");
continue;
}
cur_crt->destroy(cur_crt);
*cert = this->cert;
return TRUE;
}
return FALSE;
@ -120,6 +122,7 @@ METHOD(enumerator_t, cert_enumerator_enumerate, bool,
METHOD(enumerator_t, cert_enumerator_destroy, void,
cert_enumerator_t *this)
{
DESTROY_IF(this->cert);
this->inner->destroy(this->inner);
this->response->destroy(this->response);
free(this);

View File

@ -211,7 +211,7 @@ METHOD(tls_application_t, process, status_t,
{
DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N]",
eap_code_short_names, code);
in->destroy(in);
/* if EAP_SUCCESS check if to continue phase2 with EAP-TNC */
return (this->phase2_result == EAP_SUCCESS && code == EAP_SUCCESS) ?
start_phase2_tnc(this) : FAILED;
@ -250,6 +250,7 @@ METHOD(tls_application_t, process, status_t,
{
DBG1(DBG_IKE, "%N method not available",
eap_type_names, EAP_IDENTITY);
in->destroy(in);
return FAILED;
}
}
@ -258,6 +259,7 @@ METHOD(tls_application_t, process, status_t,
{
DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_IDENTITY);
in->destroy(in);
return FAILED;
}

View File

@ -57,6 +57,8 @@ typedef struct {
time_t notAfter;
/* identity to which the IPSECKEY belongs */
identification_t *identity;
/** most recently enumerated certificate */
certificate_t *cert;
} cert_enumerator_t;
METHOD(enumerator_t, cert_enumerator_enumerate, bool,
@ -91,28 +93,27 @@ METHOD(enumerator_t, cert_enumerator_enumerate, bool,
public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
BUILD_BLOB_DNSKEY, key,
BUILD_END);
cur_ipseckey->destroy(cur_ipseckey);
if (!public)
{
DBG1(DBG_CFG, " failed to create public key from IPSECKEY");
cur_ipseckey->destroy(cur_ipseckey);
continue;
}
*cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_TRUSTED_PUBKEY,
BUILD_PUBLIC_KEY, public,
BUILD_SUBJECT, this->identity,
BUILD_NOT_BEFORE_TIME, this->notBefore,
BUILD_NOT_AFTER_TIME, this->notAfter,
BUILD_END);
if (*cert == NULL)
DESTROY_IF(this->cert);
this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_TRUSTED_PUBKEY,
BUILD_PUBLIC_KEY, public,
BUILD_SUBJECT, this->identity,
BUILD_NOT_BEFORE_TIME, this->notBefore,
BUILD_NOT_AFTER_TIME, this->notAfter,
BUILD_END);
public->destroy(public);
if (!this->cert)
{
DBG1(DBG_CFG, " failed to create certificate from IPSECKEY");
cur_ipseckey->destroy(cur_ipseckey);
public->destroy(public);
continue;
}
cur_ipseckey->destroy(cur_ipseckey);
*cert = this->cert;
return TRUE;
}
return FALSE;
@ -121,6 +122,7 @@ METHOD(enumerator_t, cert_enumerator_enumerate, bool,
METHOD(enumerator_t, cert_enumerator_destroy, void,
cert_enumerator_t *this)
{
DESTROY_IF(this->cert);
this->inner->destroy(this->inner);
this->response->destroy(this->response);
free(this);

View File

@ -55,6 +55,13 @@ struct private_library_t {
*/
bool integrity_failed;
#ifdef LEAK_DETECTIVE
/**
* Where to write leak detective output to
*/
FILE *ld_out;
#endif
/**
* Number of times we have been initialized
*/
@ -95,32 +102,34 @@ library_t *lib = NULL;
/**
* Default leak report callback
*/
static void report_leaks(void *user, int count, size_t bytes,
backtrace_t *bt, bool detailed)
CALLBACK(report_leaks, void,
private_library_t *this, int count, size_t bytes, backtrace_t *bt,
bool detailed)
{
fprintf(stderr, "%zu bytes total, %d allocations, %zu bytes average:\n",
fprintf(this->ld_out, "%zu bytes total, %d allocations, %zu bytes average:\n",
bytes, count, bytes / count);
bt->log(bt, stderr, detailed);
bt->log(bt, this->ld_out, detailed);
}
/**
* Default leak report summary callback
*/
static void sum_leaks(void* user, int count, size_t bytes, int whitelisted)
CALLBACK(sum_leaks, void,
private_library_t *this, int count, size_t bytes, int whitelisted)
{
switch (count)
{
case 0:
fprintf(stderr, "No leaks detected");
fprintf(this->ld_out, "No leaks detected");
break;
case 1:
fprintf(stderr, "One leak detected");
fprintf(this->ld_out, "One leak detected");
break;
default:
fprintf(stderr, "%d leaks detected, %zu bytes", count, bytes);
fprintf(this->ld_out, "%d leaks detected, %zu bytes", count, bytes);
break;
}
fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
fprintf(this->ld_out, ", %d suppressed by whitelist\n", whitelisted);
}
#endif /* LEAK_DETECTIVE */
@ -166,12 +175,18 @@ void library_deinit()
this->public.integrity->destroy(this->public.integrity);
}
#ifdef LEAK_DETECTIVE
if (lib->leak_detective)
{
lib->leak_detective->report(lib->leak_detective, detailed);
lib->leak_detective->destroy(lib->leak_detective);
lib->leak_detective = NULL;
}
if (this->ld_out && this->ld_out != stderr)
{
fclose(this->ld_out);
}
#endif /* LEAK_DETECTIVE */
backtrace_deinit();
arrays_deinit();
@ -301,11 +316,22 @@ bool library_init(char *settings, const char *namespace)
backtrace_init();
#ifdef LEAK_DETECTIVE
{
FILE *out = NULL;
char *log;
log = getenv("LEAK_DETECTIVE_LOG");
if (log)
{
out = fopen(log, "a");
}
this->ld_out = out ?: stderr;
}
lib->leak_detective = leak_detective_create();
if (lib->leak_detective)
{
lib->leak_detective->set_report_cb(lib->leak_detective,
report_leaks, sum_leaks, NULL);
report_leaks, sum_leaks, this);
}
#endif /* LEAK_DETECTIVE */

View File

@ -189,7 +189,7 @@ unbound_response_t *unbound_response_create_frm_libub_response(
*/
rr_list = linked_list_create();
orig_rr_list = ldns_pkt_get_section_clone(dns_pkt, LDNS_SECTION_ANSWER);
orig_rr_list = ldns_pkt_answer(dns_pkt);
orig_rr_count = ldns_rr_list_rr_count(orig_rr_list);
for (i = 0; i < orig_rr_count; i++)
@ -253,7 +253,6 @@ unbound_response_t *unbound_response_create_frm_libub_response(
this->rr_set = rr_set_create(rr_list, rrsig_list);
ldns_pkt_free(dns_pkt);
ldns_rr_list_free(orig_rr_list);
}
return &this->public;
}

View File

@ -154,11 +154,13 @@ unbound_rr_t *unbound_rr_create_frm_ldns_rr(ldns_rr *rr)
if (status != LDNS_STATUS_OK)
{
DBG1(DBG_LIB, "failed to get the RDATA field of a DNS RR");
ldns_buffer_free(buf);
_destroy(this);
return NULL;
}
this->rdata = ldns_buffer_export(buf);
ldns_buffer_free(buf);
return &this->public;
}

View File

@ -494,7 +494,7 @@ static bool register_hooks()
* List of functions using static allocation buffers or should be suppressed
* otherwise on leak report.
*/
char *whitelist[] = {
static char *whitelist[] = {
/* backtraces, including own */
"backtrace_create",
"strerror_safe",
@ -551,6 +551,15 @@ char *whitelist[] = {
"xmlInitParserCtxt",
/* libcurl */
"Curl_client_write",
/* libsoup */
"soup_message_headers_append",
"soup_message_headers_clear",
"soup_message_headers_get_list",
"soup_message_headers_get_one",
"soup_session_abort",
"soup_session_get_type",
/* libldap */
"ldap_int_initialize",
/* ClearSilver */
"nerr_init",
/* libgcrypt */
@ -575,17 +584,28 @@ char *whitelist[] = {
/* libapr */
"apr_pool_create_ex",
/* glib */
"g_output_stream_write",
"g_resolver_lookup_by_name",
"g_signal_connect_data",
"g_socket_connection_factory_lookup_type",
"g_type_init_with_debug_flags",
"g_type_register_static",
"g_type_class_ref",
"g_type_create_instance",
"g_type_add_interface_static",
"g_type_interface_add_prerequisite",
"g_socket_connection_factory_lookup_type",
"g_private_set",
"g_queue_pop_tail",
/* libgpg */
"gpg_err_init",
/* gnutls */
"gnutls_global_init",
/* Ada runtime */
"system__tasking__initialize",
"system__tasking__initialization__abort_defer",
"system__tasking__stages__create_task",
/* in case external threads call into our code */
"thread_current_id",
};
/**

View File

@ -1,6 +1,7 @@
/*
* Copyright (C) 2011-2016 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -23,6 +24,7 @@
#include <utils/debug.h>
#include <library.h>
#include <collections/array.h>
#include <networking/host.h>
#include <utils/identification.h>
#include <attributes/attributes.h>
@ -586,11 +588,11 @@ static void resize(char *name, host_t *end)
/**
* create the lease query using the filter string
*/
static enumerator_t *create_lease_query(char *filter)
static enumerator_t *create_lease_query(char *filter, array_t **to_free)
{
enumerator_t *query;
identification_t *id = NULL;
host_t *addr = NULL;
chunk_t id_chunk = chunk_empty, addr_chunk = chunk_empty;
id_type_t id_type = 0;
u_int tstamp = 0;
bool online = FALSE, valid = FALSE, expired = FALSE;
char *value, *pos, *pool = NULL;
@ -635,18 +637,29 @@ static enumerator_t *create_lease_query(char *filter)
case FIL_ID:
if (value)
{
identification_t *id;
id = identification_create_from_string(value);
id_type = id->get_type(id);
id_chunk = chunk_clone(id->get_encoding(id));
array_insert_create(to_free, ARRAY_TAIL, id_chunk.ptr);
id->destroy(id);
}
break;
case FIL_ADDR:
if (value)
{
host_t *addr;
addr = host_create_from_string(value, 0);
}
if (!addr)
{
fprintf(stderr, "invalid 'addr' in filter string.\n");
exit(EXIT_FAILURE);
if (!addr)
{
fprintf(stderr, "invalid 'addr' in filter string.\n");
exit(EXIT_FAILURE);
}
addr_chunk = chunk_clone(addr->get_address(addr));
array_insert_create(to_free, ARRAY_TAIL, addr_chunk.ptr);
addr->destroy(addr);
}
break;
case FIL_TSTAMP:
@ -710,11 +723,11 @@ static enumerator_t *create_lease_query(char *filter)
"AND (? OR (identities.type = ? AND identities.data = ?)) "
"AND (? OR address = ?)",
DB_INT, pool == NULL, DB_TEXT, pool,
DB_INT, id == NULL,
DB_INT, id ? id->get_type(id) : 0,
DB_BLOB, id ? id->get_encoding(id) : chunk_empty,
DB_INT, addr == NULL,
DB_BLOB, addr ? addr->get_address(addr) : chunk_empty,
DB_INT, !id_chunk.ptr,
DB_INT, id_type,
DB_BLOB, id_chunk,
DB_INT, !addr_chunk.ptr,
DB_BLOB, addr_chunk,
DB_INT, tstamp == 0, DB_UINT, tstamp, DB_UINT, tstamp,
DB_INT, !valid, DB_INT, time(NULL),
DB_INT, !expired, DB_INT, time(NULL),
@ -722,14 +735,13 @@ static enumerator_t *create_lease_query(char *filter)
/* union */
DB_INT, !(valid || expired),
DB_INT, pool == NULL, DB_TEXT, pool,
DB_INT, id == NULL,
DB_INT, id ? id->get_type(id) : 0,
DB_BLOB, id ? id->get_encoding(id) : chunk_empty,
DB_INT, addr == NULL,
DB_BLOB, addr ? addr->get_address(addr) : chunk_empty,
DB_INT, !id_chunk.ptr,
DB_INT, id_type,
DB_BLOB, id_chunk,
DB_INT, !addr_chunk.ptr,
DB_BLOB, addr_chunk,
/* res */
DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT, DB_UINT);
/* id and addr leak but we can't destroy them until query is destroyed. */
return query;
}
@ -739,6 +751,7 @@ static enumerator_t *create_lease_query(char *filter)
static void leases(char *filter, bool utc)
{
enumerator_t *query;
array_t *to_free = NULL;
chunk_t address_chunk, identity_chunk;
int identity_type;
char *name;
@ -748,7 +761,7 @@ static void leases(char *filter, bool utc)
identification_t *identity;
bool found = FALSE;
query = create_lease_query(filter);
query = create_lease_query(filter, &to_free);
if (!query)
{
fprintf(stderr, "querying leases failed.\n");
@ -809,6 +822,10 @@ static void leases(char *filter, bool utc)
identity->destroy(identity);
}
query->destroy(query);
if (to_free)
{
array_destroy_function(to_free, (void*)free, NULL);
}
if (!found)
{
fprintf(stderr, "no matching leases found.\n");

View File

@ -357,7 +357,7 @@ do
##########################################################################
# copy test specific configurations to uml hosts and clear auth.log files
# copy test specific configurations to hosts and clear log files
#
DBDIR=/etc/db.d
@ -409,6 +409,16 @@ do
ssh $SSHCONF root@`eval echo \\\$ipv4_$host` 'conntrack -F' >/dev/null 2>&1
done
##########################################################################
# remove leak detective log on all hosts
#
export LEAK_DETECTIVE_LOG=/var/log/leak-detective.log
for host in $STRONGSWANHOSTS
do
ssh $SSHCONF root@`eval echo \\\$ipv4_$host` 'rm -f $LEAK_DETECTIVE_LOG' >/dev/null 2>&1
done
##########################################################################
# flush IPsec state on all hosts
#
@ -485,18 +495,6 @@ do
}' $TESTDIR/evaltest.dat` >> $CONSOLE_LOG 2>&1
##########################################################################
# set counters
#
if [ $STATUS = "failed" ]
then
let "failed_cnt += 1"
else
let "passed_cnt += 1"
fi
##########################################################################
# log statusall and listall output
# get copies of ipsec.conf, ipsec.secrets
@ -802,6 +800,25 @@ do
fi
done
##########################################################################
# make sure there were no leaks
#
for host in $STRONGSWANHOSTS
do
eval HOSTLOGIN=root@\$ipv4_${host}
LEAKS=`ssh $SSHCONF $HOSTLOGIN 'cat $LEAK_DETECTIVE_LOG 2>/dev/null | grep -v "No leaks detected.*"'`
if [ -n "$LEAKS" ]
then
echo -e "\n$host# cat $LEAK_DETECTIVE_LOG [NO]" >> $CONSOLE_LOG
echo "$LEAKS" >> $CONSOLE_LOG
echo "<<< $host $LEAK_DETECTIVE_LOG >>>" >> $CONSOLE_LOG
STATUS="failed"
fi
done
##########################################################################
# get a copy of /var/log/auth.log
#
@ -858,6 +875,18 @@ do
$DIR/scripts/restore-defaults $testname
##########################################################################
# set counters
#
if [ $STATUS = "failed" ]
then
let "failed_cnt += 1"
else
let "passed_cnt += 1"
fi
##########################################################################
# write test status to html file
#

View File

@ -12,3 +12,4 @@ PermitEmptyPasswords yes
PrintMotd no
PrintLastLog no
UsePAM no
AcceptEnv LEAK_DETECTIVE_LOG

View File

@ -1,6 +1,7 @@
Host *
# debian default
SendEnv LANG LC_*
SendEnv LEAK_DETECTIVE_LOG
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
GSSAPIAuthentication yes

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = pem pkcs1 pkcs8 random nonce x509 revocation openssl soup stroke kernel-libipsec kernel-netlink socket-default updown
load = pem pkcs1 pkcs8 random nonce x509 revocation openssl curl stroke kernel-libipsec kernel-netlink socket-default updown
initiator_only = yes

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = pem pkcs1 pkcs8 random nonce x509 revocation openssl soup stroke kernel-libipsec kernel-netlink socket-default updown
load = pem pkcs1 pkcs8 random nonce x509 revocation openssl curl stroke kernel-libipsec kernel-netlink socket-default updown
initiator_only = yes

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = pem pkcs1 pkcs8 random nonce x509 revocation openssl soup stroke kernel-libipsec kernel-netlink socket-default updown
load = pem pkcs1 pkcs8 random nonce x509 revocation openssl curl stroke kernel-libipsec kernel-netlink socket-default updown
plugins {
openssl {