# Commit a8bc99b981c5ad773bd646f5986e616d26fb94d7 # Date 2015-07-16 11:50:07 +0200 # Author Elena Ufimtseva # Committer Jan Beulich dmar: device scope mem leak fix Release memory allocated for scope.devices dmar units on various failure paths and when disabling dmar. Set device count after sucessfull memory allocation, not before, in device scope parsing function. Signed-off-by: Elena Ufimtseva Reviewed-by: Jan Beulich Acked-by: Yang Zhang # Commit 132231d10343608faf5892785a08acc500326d04 # Date 2015-07-16 15:23:37 +0200 # Author Andrew Cooper # Committer Jan Beulich dmar: fix double free in error paths following c/s a8bc99b Several error paths would end up freeing scope->devices twice. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- a/xen/drivers/passthrough/vtd/dmar.c +++ b/xen/drivers/passthrough/vtd/dmar.c @@ -80,6 +80,16 @@ static int __init acpi_register_rmrr_uni return 0; } +static void scope_devices_free(struct dmar_scope *scope) +{ + if ( !scope ) + return; + + scope->devices_cnt = 0; + xfree(scope->devices); + scope->devices = NULL; +} + static void __init disable_all_dmar_units(void) { struct acpi_drhd_unit *drhd, *_drhd; @@ -89,16 +99,19 @@ static void __init disable_all_dmar_unit list_for_each_entry_safe ( drhd, _drhd, &acpi_drhd_units, list ) { list_del(&drhd->list); + scope_devices_free(&drhd->scope); xfree(drhd); } list_for_each_entry_safe ( rmrr, _rmrr, &acpi_rmrr_units, list ) { list_del(&rmrr->list); + scope_devices_free(&rmrr->scope); xfree(rmrr); } list_for_each_entry_safe ( atsr, _atsr, &acpi_atsr_units, list ) { list_del(&atsr->list); + scope_devices_free(&atsr->scope); xfree(atsr); } } @@ -317,13 +330,13 @@ static int __init acpi_parse_dev_scope( if ( (cnt = scope_device_count(start, end)) < 0 ) return cnt; - scope->devices_cnt = cnt; if ( cnt > 0 ) { scope->devices = xzalloc_array(u16, cnt); if ( !scope->devices ) return -ENOMEM; } + scope->devices_cnt = cnt; while ( start < end ) { @@ -426,7 +439,7 @@ static int __init acpi_parse_dev_scope( out: if ( ret ) - xfree(scope->devices); + scope_devices_free(scope); return ret; } @@ -541,6 +554,7 @@ acpi_parse_one_drhd(struct acpi_dmar_hea " Workaround BIOS bug: ignore the DRHD due to all " "devices under its scope are not PCI discoverable!\n"); + scope_devices_free(&dmaru->scope); iommu_free(dmaru); xfree(dmaru); } @@ -561,9 +575,11 @@ acpi_parse_one_drhd(struct acpi_dmar_hea out: if ( ret ) { + scope_devices_free(&dmaru->scope); iommu_free(dmaru); xfree(dmaru); } + return ret; } @@ -657,6 +673,7 @@ acpi_parse_one_rmrr(struct acpi_dmar_hea " Ignore the RMRR (%"PRIx64", %"PRIx64") due to " "devices under its scope are not PCI discoverable!\n", rmrru->base_address, rmrru->end_address); + scope_devices_free(&rmrru->scope); xfree(rmrru); } else if ( base_addr > end_addr ) @@ -664,6 +681,7 @@ acpi_parse_one_rmrr(struct acpi_dmar_hea dprintk(XENLOG_WARNING VTDPREFIX, " The RMRR (%"PRIx64", %"PRIx64") is incorrect!\n", rmrru->base_address, rmrru->end_address); + scope_devices_free(&rmrru->scope); xfree(rmrru); ret = -EFAULT; } @@ -726,7 +744,10 @@ acpi_parse_one_atsr(struct acpi_dmar_hea } if ( ret ) + { + scope_devices_free(&atsru->scope); xfree(atsru); + } else acpi_register_atsr_unit(atsru); return ret;