Page MenuHomeFreeBSD

D58724.id183668.diff
No OneTemporary

D58724.id183668.diff

Index: sys/x86/iommu/amd_drv.c
===================================================================
--- sys/x86/iommu/amd_drv.c
+++ 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);
}
@@ -656,19 +685,57 @@
amdiommu_find_unit_scan_ivrs(ACPI_IVRS_DE_HEADER *d, size_t tlen,
struct ivhd_find_unit *ifu)
{
+ ACPI_IVRS_DEVICE_HID *dh;
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;
- if (d->Type == ACPI_IVRS_TYPE_PAD4) {
+ db = (char *)d;
+ de = db + tlen;
+ while (db < de) {
+ remaining = de - db;
+ d = (ACPI_IVRS_DE_HEADER *)db;
+
+ /* Determine and validate the complete entry before using it. */
+ if (d->Type == ACPI_IVRS_TYPE_START) {
+ len = 2 * sizeof(ACPI_IVRS_DEVICE4);
+ } else if (d->Type == ACPI_IVRS_TYPE_ALIAS_START) {
+ len = sizeof(ACPI_IVRS_DEVICE8A) +
+ sizeof(ACPI_IVRS_DEVICE4);
+ } else if (d->Type == ACPI_IVRS_TYPE_EXT_START) {
+ len = sizeof(ACPI_IVRS_DEVICE8B) +
+ sizeof(ACPI_IVRS_DEVICE4);
+ } else if (d->Type == ACPI_IVRS_TYPE_HID) {
+ if (remaining < sizeof(*dh)) {
+ printf("amdiommu: truncated IVRS HID entry\n");
+ return (false);
+ }
+ dh = (ACPI_IVRS_DEVICE_HID *)db;
+ if (dh->UidLength > remaining - sizeof(*dh)) {
+ printf("amdiommu: truncated IVRS HID UID\n");
+ return (false);
+ }
+ len = sizeof(*dh) + dh->UidLength;
+ } else 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);
+ return (false);
+ }
+ if (len > remaining) {
+ printf("amdiommu: truncated IVRS device entry %#x\n",
+ d->Type);
+ return (false);
+ }
+
+ if (d->Type == ACPI_IVRS_TYPE_PAD4) {
} else if (d->Type == ACPI_IVRS_TYPE_ALL) {
ACPI_IVRS_DEVICE4 *d4;
d4 = (ACPI_IVRS_DEVICE4 *)db;
- len = sizeof(*d4);
ifu->dte = d4->Header.DataSetting;
} else if (d->Type == ACPI_IVRS_TYPE_SELECT) {
ACPI_IVRS_DEVICE4 *d4;
@@ -679,7 +746,6 @@
ifu->rid_real = ifu->rid;
return (true);
}
- len = sizeof(*d4);
} else if (d->Type == ACPI_IVRS_TYPE_START) {
ACPI_IVRS_DEVICE4 *d4, *d4n;
@@ -696,9 +762,7 @@
ifu->rid_real = ifu->rid;
return (true);
}
- len = 2 * sizeof(*d4);
} else if (d->Type == ACPI_IVRS_TYPE_PAD8) {
- len = sizeof(ACPI_IVRS_DEVICE8A);
} else if (d->Type == ACPI_IVRS_TYPE_ALIAS_SELECT) {
ACPI_IVRS_DEVICE8A *d8a;
@@ -708,7 +772,6 @@
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;
@@ -726,7 +789,6 @@
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;
@@ -737,7 +799,6 @@
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;
@@ -749,14 +810,13 @@
"(%#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;
@@ -770,29 +830,10 @@
ifu->rid_real = d8c->UsedId;
return (true);
}
- len = sizeof(*d8c);
} else if (d->Type == ACPI_IVRS_TYPE_HID) {
- ACPI_IVRS_DEVICE_HID *dh;
-
- 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);
- return (false);
- }
}
+ db += len;
}
return (false);
}
@@ -810,8 +851,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 +873,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
Mon, Aug 17, 4:00 PM (33 m, 2 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36858880
Default Alt Text
D58724.id183668.diff (6 KB)

Event Timeline