Prevent double free with invalid verity partition.

It is possible to trigger a double free with an invalid verity
partition. All it takes is an unknown hash algorithm, which makes it
a bit more likely than a completely broken partition header. But all
it takes is an error return value of VERITY_read_sb() or strdup().

If crypt_load fails before setting cd->type, crypt_free will handle
the union as if it was of type "none", which means it will call free()
for "active_name", a field which is only properly set up when the
type was actually "none".

In all other cases, "active_name" contains the first 4 or 8 bytes of
the actually used header structure. Fortunately it can be only a
pointer or NULL, so an attacker has no direct control of the value.
Nonetheless it can easily trigger a double free.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
This commit is contained in:
Tobias Stoeckmann
2017-05-01 15:06:26 +02:00
committed by Milan Broz
parent 3f9346836e
commit 44d5269c0a
2 changed files with 12 additions and 3 deletions

View File

@@ -603,6 +603,15 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit
if (r < 0)
return r;
//FIXME: use crypt_free
if (!cd->type && !(cd->type = strdup(CRYPT_VERITY))) {
free(CONST_CAST(void*)cd->u.verity.hdr.hash_name);
free(CONST_CAST(void*)cd->u.verity.hdr.salt);
free(cd->u.verity.uuid);
crypt_memzero(&cd->u.verity.hdr, sizeof(cd->u.verity.hdr));
return -ENOMEM;
}
if (params)
cd->u.verity.hdr.flags = params->flags;
@@ -611,9 +620,6 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit
if (cd->u.verity.root_hash_size > 4096)
return -EINVAL;
if (!cd->type && !(cd->type = strdup(CRYPT_VERITY)))
return -ENOMEM;
if (params && params->data_device &&
(r = crypt_set_data_device(cd, params->data_device)) < 0)
return r;

View File

@@ -123,6 +123,7 @@ int VERITY_read_sb(struct crypt_device *cd,
log_err(cd, _("Hash algorithm %s not supported.\n"),
params->hash_name);
free(CONST_CAST(char*)params->hash_name);
params->hash_name = NULL;
return -EINVAL;
}
@@ -130,11 +131,13 @@ int VERITY_read_sb(struct crypt_device *cd,
if (params->salt_size > sizeof(sb.salt)) {
log_err(cd, _("VERITY header corrupted.\n"));
free(CONST_CAST(char*)params->hash_name);
params->hash_name = NULL;
return -EINVAL;
}
params->salt = malloc(params->salt_size);
if (!params->salt) {
free(CONST_CAST(char*)params->hash_name);
params->hash_name = NULL;
return -ENOMEM;
}
memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);