[PATCH 4/4] PCI/sysfs: Pass the device name length in UTF-16 code units
Krzysztof Wilczyński <[email protected]>
| Newsgroups | org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
Currently, dsm_label_utf16s_to_utf8s() passes the ACPI buffer
length to utf16s_to_utf8s() unchanged. The Device Name _DSM may
return the device name as a buffer holding a UTF-16 string, and
the ACPI length counts bytes while the converter counts wchar_t
elements. The converter therefore receives a count twice the
number of code units the buffer holds, and that count is its only
bound on the input.
A NUL code unit ends the conversion early, so a name that carries
one is converted correctly and the error stays hidden. ACPICA
zeroes the entire result allocation, and the padding placed after
the buffer supplies that NUL for most lengths. Lengths that leave
no padding, or a single byte of it, do not, and the conversion
then runs up to its own length in bytes past the end of the
allocation. The bytes beyond the allocation are decoded into the
"label" attribute, which is world readable.
Thus, divide the buffer length by the size of wchar_t so that the
converter receives a count of code units. The division truncates,
so the converter is never told to read more bytes than the buffer
holds, including for an odd length.
Reaching the out of bounds read needs firmware that returns the
name as a buffer and omits the terminator.
Fixes: 6058989bad05 ("PCI: Export ACPI _DSM provided firmware instance number and string name to sysfs")
Cc: [email protected]
Signed-off-by: Krzysztof Wilczyński <[email protected]>
---
drivers/pci/pci-label.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index abb941530c56..08c461f1142d 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -144,7 +144,7 @@ static int dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
int len;
len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer,
- obj->buffer.length,
+ obj->buffer.length / sizeof(wchar_t),
UTF16_LITTLE_ENDIAN,
buf, PAGE_SIZE - 1);
buf[len++] = '\n';
--
2.55.0