Page MenuHomeFreeBSD

D58724.id183686.diff
No OneTemporary

D58724.id183686.diff

diff --git a/sys/x86/iommu/amd_drv.c b/sys/x86/iommu/amd_drv.c
--- a/sys/x86/iommu/amd_drv.c
+++ b/sys/x86/iommu/amd_drv.c
@@ -91,9 +91,26 @@
int type, ACPI_TABLE_IVRS *ivrs_tbl)
{
char *ptr, *ptrend;
+ size_t min_length, remaining;
bool done;
done = false;
+ if (ivrs_tbl->Header.Length < sizeof(*ivrs_tbl)) {
+ printf("amdiommu_iterate_tbl: truncated IVRS table\n");
+ return (false);
+ }
+ switch (type) {
+ case ACPI_IVRS_TYPE_HARDWARE2:
+ case ACPI_IVRS_TYPE_HARDWARE3:
+ min_length = sizeof(ACPI_IVRS_HARDWARE2);
+ break;
+ case ACPI_IVRS_TYPE_HARDWARE1:
+ min_length = sizeof(ACPI_IVRS_HARDWARE1);
+ break;
+ default:
+ min_length = sizeof(ACPI_IVRS_HEADER);
+ break;
+ }
ptr = (char *)ivrs_tbl + sizeof(*ivrs_tbl);
ptrend = (char *)ivrs_tbl + ivrs_tbl->Header.Length;
for (;;) {
@@ -101,18 +118,30 @@
if (ptr >= ptrend)
break;
+ remaining = ptrend - ptr;
+ if (remaining < sizeof(*ivrsh)) {
+ printf("amdiommu_iterate_tbl: truncated IVRS subtable header\n");
+ break;
+ }
ivrsh = (ACPI_IVRS_HEADER *)ptr;
- if (ivrsh->Length <= 0) {
+ if (ivrsh->Length < sizeof(*ivrsh) ||
+ ivrsh->Length > remaining) {
printf("amdiommu_iterate_tbl: corrupted IVRS table, "
- "length %d\n", ivrsh->Length);
+ "subtable length %u, remaining %zu\n",
+ ivrsh->Length, remaining);
break;
}
- ptr += ivrsh->Length;
if (ivrsh->Type == type) {
+ if (ivrsh->Length < min_length) {
+ printf("amdiommu_iterate_tbl: truncated IVRS "
+ "subtable type %#x\n", type);
+ break;
+ }
done = iter((void *)ivrsh, arg);
if (done)
break;
}
+ ptr += ivrsh->Length;
}
return (done);
}
@@ -657,32 +686,43 @@
struct ivhd_find_unit *ifu)
{
char *db, *de;
+ size_t remaining;
size_t len;
- for (de = (char *)d + tlen; (char *)d < de;
- d = (ACPI_IVRS_DE_HEADER *)(db + len)) {
- db = (char *)d;
+ db = (char *)d;
+ de = db + tlen;
+ while (db < de) {
+ remaining = de - db;
+ d = (ACPI_IVRS_DE_HEADER *)db;
+ if (remaining < sizeof(*d)) {
+ printf("amdiommu: truncated IVRS device entry header\n");
+ return (false);
+ }
+
if (d->Type == ACPI_IVRS_TYPE_PAD4) {
len = sizeof(ACPI_IVRS_DEVICE4);
} else if (d->Type == ACPI_IVRS_TYPE_ALL) {
ACPI_IVRS_DEVICE4 *d4;
- d4 = (ACPI_IVRS_DEVICE4 *)db;
len = sizeof(*d4);
+ d4 = (ACPI_IVRS_DEVICE4 *)db;
ifu->dte = d4->Header.DataSetting;
} else if (d->Type == ACPI_IVRS_TYPE_SELECT) {
ACPI_IVRS_DEVICE4 *d4;
+ len = sizeof(*d4);
d4 = (ACPI_IVRS_DEVICE4 *)db;
if (d4->Header.Id == ifu->rid) {
ifu->dte = d4->Header.DataSetting;
ifu->rid_real = ifu->rid;
return (true);
}
- len = sizeof(*d4);
} else if (d->Type == ACPI_IVRS_TYPE_START) {
ACPI_IVRS_DEVICE4 *d4, *d4n;
+ len = 2 * sizeof(*d4);
+ if (len > remaining)
+ goto truncated;
d4 = (ACPI_IVRS_DEVICE4 *)db;
d4n = d4 + 1;
if (d4n->Header.Type != ACPI_IVRS_TYPE_END) {
@@ -696,23 +736,29 @@
ifu->rid_real = ifu->rid;
return (true);
}
- len = 2 * sizeof(*d4);
} else if (d->Type == ACPI_IVRS_TYPE_PAD8) {
len = sizeof(ACPI_IVRS_DEVICE8A);
+ if (len > remaining)
+ goto truncated;
} else if (d->Type == ACPI_IVRS_TYPE_ALIAS_SELECT) {
ACPI_IVRS_DEVICE8A *d8a;
+ len = sizeof(*d8a);
+ if (len > remaining)
+ goto truncated;
d8a = (ACPI_IVRS_DEVICE8A *)db;
if (d8a->Header.Id == ifu->rid) {
ifu->dte = d8a->Header.DataSetting;
ifu->rid_real = d8a->UsedId;
return (true);
}
- len = sizeof(*d8a);
} else if (d->Type == ACPI_IVRS_TYPE_ALIAS_START) {
ACPI_IVRS_DEVICE8A *d8a;
ACPI_IVRS_DEVICE4 *d4;
+ len = sizeof(*d8a) + sizeof(*d4);
+ if (len > remaining)
+ goto truncated;
d8a = (ACPI_IVRS_DEVICE8A *)db;
d4 = (ACPI_IVRS_DEVICE4 *)(d8a + 1);
if (d4->Header.Type != ACPI_IVRS_TYPE_END) {
@@ -726,10 +772,12 @@
ifu->rid_real = d8a->UsedId;
return (true);
}
- len = sizeof(*d8a) + sizeof(*d4);
} else if (d->Type == ACPI_IVRS_TYPE_EXT_SELECT) {
ACPI_IVRS_DEVICE8B *d8b;
+ len = sizeof(*d8b);
+ if (len > remaining)
+ goto truncated;
d8b = (ACPI_IVRS_DEVICE8B *)db;
if (d8b->Header.Id == ifu->rid) {
ifu->dte = d8b->Header.DataSetting;
@@ -737,11 +785,13 @@
ifu->edte = d8b->ExtendedData;
return (true);
}
- len = sizeof(*d8b);
} else if (d->Type == ACPI_IVRS_TYPE_EXT_START) {
ACPI_IVRS_DEVICE8B *d8b;
ACPI_IVRS_DEVICE4 *d4;
+ len = sizeof(*d8b) + sizeof(*d4);
+ if (len > remaining)
+ goto truncated;
d8b = (ACPI_IVRS_DEVICE8B *)db;
d4 = (ACPI_IVRS_DEVICE4 *)(db + sizeof(*d8b));
if (d4->Header.Type != ACPI_IVRS_TYPE_END) {
@@ -749,17 +799,19 @@
"(%#x)\n", d4->Header.Type);
return (false);
}
- if (d8b->Header.Id >= ifu->rid &&
+ if (d8b->Header.Id <= ifu->rid &&
ifu->rid <= d4->Header.Id) {
ifu->dte = d8b->Header.DataSetting;
ifu->rid_real = ifu->rid;
ifu->edte = d8b->ExtendedData;
return (true);
}
- len = sizeof(*d8b) + sizeof(*d4);
} else if (d->Type == ACPI_IVRS_TYPE_SPECIAL) {
ACPI_IVRS_DEVICE8C *d8c;
+ len = sizeof(*d8c);
+ if (len > remaining)
+ goto truncated;
d8c = (ACPI_IVRS_DEVICE8C *)db;
if (((ifu->type == IFU_DEV_IOAPIC &&
d8c->Variety == ACPI_IVHD_IOAPIC) ||
@@ -770,31 +822,39 @@
ifu->rid_real = d8c->UsedId;
return (true);
}
- len = sizeof(*d8c);
} else if (d->Type == ACPI_IVRS_TYPE_HID) {
ACPI_IVRS_DEVICE_HID *dh;
+ len = sizeof(*dh);
+ if (len > remaining) {
+ printf("amdiommu: truncated IVRS HID entry\n");
+ return (false);
+ }
dh = (ACPI_IVRS_DEVICE_HID *)db;
- len = sizeof(*dh) + dh->UidLength;
- /* XXXKIB */
- } else {
-#if 0
- printf("amdiommu: unknown IVRS device entry type %#x\n",
- d->Type);
-#endif
- if (d->Type <= 63)
- len = sizeof(ACPI_IVRS_DEVICE4);
- else if (d->Type <= 127)
- len = sizeof(ACPI_IVRS_DEVICE8A);
- else {
- printf("amdiommu: abort, cannot "
- "advance iterator, item type %#x\n",
- d->Type);
+ if (dh->UidLength > remaining - len) {
+ printf("amdiommu: truncated IVRS HID UID\n");
return (false);
}
+ len += dh->UidLength;
+ /* XXXKIB */
+ } else if (d->Type <= 63) {
+ len = sizeof(ACPI_IVRS_DEVICE4);
+ } else if (d->Type <= 127) {
+ len = sizeof(ACPI_IVRS_DEVICE8A);
+ if (len > remaining)
+ goto truncated;
+ } else {
+ printf("amdiommu: abort, cannot advance iterator, "
+ "item type %#x\n", d->Type);
+ return (false);
}
+ db += len;
}
return (false);
+
+truncated:
+ printf("amdiommu: truncated IVRS device entry %#x\n", d->Type);
+ return (false);
}
static bool
@@ -810,8 +870,11 @@
if (ifu->domain != ivrs->PciSegmentGroup)
return (false);
+ if (ivrs->Header.Length < sizeof(*ivrs))
+ return (false);
d = (ACPI_IVRS_DE_HEADER *)(ivrs + 1);
- res = amdiommu_find_unit_scan_ivrs(d, ivrs->Header.Length, ifu);
+ res = amdiommu_find_unit_scan_ivrs(d,
+ ivrs->Header.Length - sizeof(*ivrs), ifu);
if (res)
ifu->device_id = ivrs->Header.DeviceId;
return (res);
@@ -829,8 +892,11 @@
if (ifu->domain != ivrs->PciSegmentGroup)
return (false);
+ if (ivrs->Header.Length < sizeof(*ivrs))
+ return (false);
d = (ACPI_IVRS_DE_HEADER *)(ivrs + 1);
- res = amdiommu_find_unit_scan_ivrs(d, ivrs->Header.Length, ifu);
+ res = amdiommu_find_unit_scan_ivrs(d,
+ ivrs->Header.Length - sizeof(*ivrs), ifu);
if (res)
ifu->device_id = ivrs->Header.DeviceId;
return (res);

File Metadata

Mime Type
text/plain
Expires
Tue, Aug 18, 1:07 AM (8 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36344914
Default Alt Text
D58724.id183686.diff (7 KB)

Event Timeline