Fix potential double free in cert writing code

In case an entry with the given OID already exists in the list passed to
mbedtls_asn1_store_named_data() and there is not enough memory to allocate
room for the new value, the existing entry will be freed but the preceding
entry in the list will sill hold a pointer to it. (And the following entries
in the list are no longer reachable.) This results in memory leak or a double
free.

The issue is we want to leave the list in a consistent state on allocation
failure. (We could add a warning that the list is left in inconsistent state
when the function returns NULL, but behaviour changes that require more care
from the user are undesirable, especially in a stable branch.)

The chosen solution is a bit inefficient in that there is a time where both
blocks are allocated, but at least it's safe and this should trump efficiency
here: this code is only used for generating certificates, which is unlikely to
be done on very constrained devices, or to be in the critical loop of
anything. Also, the sizes involved should be fairly small anyway.

fixes #367
This commit is contained in:
Manuel Pégourié-Gonnard 2015-12-10 10:50:51 +01:00
parent 1630888aa0
commit 97b5209bc0
2 changed files with 18 additions and 12 deletions

View File

@ -1,5 +1,12 @@
mbed TLS ChangeLog (Sorted per branch, date) mbed TLS ChangeLog (Sorted per branch, date)
= mbed TLS 2.2.1 released 2015-12-xx
Security
* Fix potential double free when mbedtls_asn1_store_named_data() fails to
allocate memory. Only used for certificate generation, not triggerable
remotely in SSL/TLS. Found by Rafał Przywara. #367
= mbed TLS 2.2.0 released 2015-11-04 = mbed TLS 2.2.0 released 2015-11-04
Security Security

View File

@ -339,19 +339,18 @@ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data
} }
else if( cur->val.len < val_len ) else if( cur->val.len < val_len )
{ {
// Enlarge existing value buffer if needed /*
// * Enlarge existing value buffer if needed
mbedtls_free( cur->val.p ); * Preserve old data until the allocation succeeded, to leave list in
cur->val.p = NULL; * a consistent state in case allocation fails.
*/
cur->val.len = val_len; void *p = mbedtls_calloc( 1, val_len );
cur->val.p = mbedtls_calloc( 1, val_len ); if( p == NULL )
if( cur->val.p == NULL )
{
mbedtls_free( cur->oid.p );
mbedtls_free( cur );
return( NULL ); return( NULL );
}
mbedtls_free( cur->val.p );
cur->val.p = p;
cur->val.len = val_len;
} }
if( val != NULL ) if( val != NULL )