Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI / PCI: Fix sysfs acpi_index and label errors

Fix errors in handling "device label" _DSM return values.

If _DSM returns a Unicode string, the ACPI type is ACPI_TYPE_BUFFER, not
ACPI_TYPE_STRING. Fix dsm_label_utf16s_to_utf8s() to convert UTF-16 from
acpi_object->buffer instead of acpi_object->string.

Prior to v3.14, we accepted Unicode labels (ACPI_TYPE_BUFFER return
values). But after 1d0fcef73283, we accepted only ASCII (ACPI_TYPE_STRING)
(and we incorrectly tried to convert those ASCII labels from UTF-16 to
UTF-8).

Rejecting Unicode labels made us return -EPERM when reading sysfs
"acpi_index" or "label" files, which in turn caused on-board network
interfaces on a Dell PowerEdge E420 to be renamed (by udev net_id internal)
from eno1/eno2 to enp2s0f0/enp2s0f1.

Fix this by accepting either ACPI_TYPE_STRING (and treating it as ASCII) or
ACPI_TYPE_BUFFER (and converting from UTF-16 to UTF-8).

[bhelgaas: changelog]
Fixes: 1d0fcef73283 ("ACPI / PCI: replace open-coded _DSM code with helper functions")
Signed-off-by: Simone Gotti <simone.gotti@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Jiang Liu <jiang.liu@linux.intel.com>
CC: stable@vger.kernel.org # v3.14+

authored by

Simone Gotti and committed by
Bjorn Helgaas
dcfa9be8 7f105d31

+12 -6
+12 -6
drivers/pci/pci-label.c
··· 161 161 static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) 162 162 { 163 163 int len; 164 - len = utf16s_to_utf8s((const wchar_t *)obj->string.pointer, 165 - obj->string.length, 164 + len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer, 165 + obj->buffer.length, 166 166 UTF16_LITTLE_ENDIAN, 167 167 buf, PAGE_SIZE); 168 168 buf[len] = '\n'; ··· 187 187 tmp = obj->package.elements; 188 188 if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 && 189 189 tmp[0].type == ACPI_TYPE_INTEGER && 190 - tmp[1].type == ACPI_TYPE_STRING) { 190 + (tmp[1].type == ACPI_TYPE_STRING || 191 + tmp[1].type == ACPI_TYPE_BUFFER)) { 191 192 /* 192 193 * The second string element is optional even when 193 194 * this _DSM is implemented; when not implemented, 194 195 * this entry must return a null string. 195 196 */ 196 - if (attr == ACPI_ATTR_INDEX_SHOW) 197 + if (attr == ACPI_ATTR_INDEX_SHOW) { 197 198 scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value); 198 - else if (attr == ACPI_ATTR_LABEL_SHOW) 199 - dsm_label_utf16s_to_utf8s(tmp + 1, buf); 199 + } else if (attr == ACPI_ATTR_LABEL_SHOW) { 200 + if (tmp[1].type == ACPI_TYPE_STRING) 201 + scnprintf(buf, PAGE_SIZE, "%s\n", 202 + tmp[1].string.pointer); 203 + else if (tmp[1].type == ACPI_TYPE_BUFFER) 204 + dsm_label_utf16s_to_utf8s(tmp + 1, buf); 205 + } 200 206 len = strlen(buf) > 0 ? strlen(buf) : -1; 201 207 } 202 208