From 54e5bb46597e5eba63e460a1f96eb2021dc71fec Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:12 +0800 Subject: PCI / pci-label: release allocated ACPI object on error recovery path Function dsm_get_label() leaks the returned ACPI object if obj->package.count is not 2, so fix the possible memory leak. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-label.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index d51f45aa669e..f6e01a500d79 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -233,11 +233,7 @@ dsm_get_label(acpi_handle handle, int func, return -1; obj = (union acpi_object *)output->pointer; - - switch (obj->type) { - case ACPI_TYPE_PACKAGE: - if (obj->package.count != 2) - break; + if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2) { len = obj->package.elements[0].integer.value; if (buf) { if (attribute == ACPI_ATTR_INDEX_SHOW) @@ -250,10 +246,10 @@ dsm_get_label(acpi_handle handle, int func, } kfree(output->pointer); return len; - break; - default: - kfree(output->pointer); } + + kfree(output->pointer); + return -1; } -- cgit v1.2.3 From 1d0fcef732832432aee47cb75bf4a2cb3107be64 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:13 +0800 Subject: ACPI / PCI: replace open-coded _DSM code with helper functions Use helper functions to simplify _DSM related code in pci-label driver. Also enforce more strict checks on objects returned by _DSM method. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-label.c | 121 ++++++++++++++---------------------------------- 1 file changed, 34 insertions(+), 87 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index f6e01a500d79..f12dcd1dc208 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -195,80 +195,58 @@ enum acpi_attr_enum { static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) { int len; - len = utf16s_to_utf8s((const wchar_t *)obj-> - package.elements[1].string.pointer, - obj->package.elements[1].string.length, + len = utf16s_to_utf8s((const wchar_t *)obj->string.pointer, + obj->string.length, UTF16_LITTLE_ENDIAN, buf, PAGE_SIZE); buf[len] = '\n'; } static int -dsm_get_label(acpi_handle handle, int func, - struct acpi_buffer *output, - char *buf, enum acpi_attr_enum attribute) +dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) { - struct acpi_object_list input; - union acpi_object params[4]; - union acpi_object *obj; - int len = 0; - - int err; - - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(device_label_dsm_uuid); - params[0].buffer.pointer = (char *)device_label_dsm_uuid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 0x02; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - err = acpi_evaluate_object(handle, "_DSM", &input, output); - if (err) + acpi_handle handle; + union acpi_object *obj, *tmp; + int len = -1; + + handle = ACPI_HANDLE(dev); + if (!handle) return -1; - obj = (union acpi_object *)output->pointer; - if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2) { - len = obj->package.elements[0].integer.value; + obj = acpi_evaluate_dsm(handle, device_label_dsm_uuid, 0x2, + DEVICE_LABEL_DSM, NULL); + if (!obj) + return -1; + + tmp = obj->package.elements; + if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 && + tmp[0].type == ACPI_TYPE_INTEGER && + tmp[1].type == ACPI_TYPE_STRING) { + len = tmp[0].integer.value; if (buf) { - if (attribute == ACPI_ATTR_INDEX_SHOW) + /* + * This second string element is optional even when + * this _DSM is implemented; when not implemented, + * this entry must return a null string. + */ + if (attr == ACPI_ATTR_INDEX_SHOW) scnprintf(buf, PAGE_SIZE, "%llu\n", - obj->package.elements[0].integer.value); - else if (attribute == ACPI_ATTR_LABEL_SHOW) - dsm_label_utf16s_to_utf8s(obj, buf); - kfree(output->pointer); - return strlen(buf); + tmp->integer.value); + else if (attr == ACPI_ATTR_LABEL_SHOW) + dsm_label_utf16s_to_utf8s(tmp + 1, buf); + len = strlen(buf) > 0 ? strlen(buf) : -1; } - kfree(output->pointer); - return len; } - kfree(output->pointer); + ACPI_FREE(obj); - return -1; + return len; } static bool device_has_dsm(struct device *dev) { - acpi_handle handle; - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - - handle = ACPI_HANDLE(dev); - - if (!handle) - return FALSE; - - if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL, - ACPI_ATTR_NONE) > 0) - return TRUE; - - return FALSE; + return dsm_get_label(dev, NULL, ACPI_ATTR_NONE) > 0; } static umode_t @@ -287,44 +265,13 @@ acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n) static ssize_t acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_handle handle; - int length; - - handle = ACPI_HANDLE(dev); - - if (!handle) - return -1; - - length = dsm_get_label(handle, DEVICE_LABEL_DSM, - &output, buf, ACPI_ATTR_LABEL_SHOW); - - if (length < 1) - return -1; - - return length; + return dsm_get_label(dev, buf, ACPI_ATTR_LABEL_SHOW); } static ssize_t acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_handle handle; - int length; - - handle = ACPI_HANDLE(dev); - - if (!handle) - return -1; - - length = dsm_get_label(handle, DEVICE_LABEL_DSM, - &output, buf, ACPI_ATTR_INDEX_SHOW); - - if (length < 0) - return -1; - - return length; - + return dsm_get_label(dev, buf, ACPI_ATTR_INDEX_SHOW); } static struct device_attribute acpi_attr_label = { -- cgit v1.2.3 From 2fc59fe2ecdca56a68728b6091590c07bb3e358d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:14 +0800 Subject: PCI / pci-label: treat PCI label with index 0 as valid label Current pci-label driver detects ACPI label by checking label index returned by ACPI _DSM method, and treats it as valid if label index is positive. According to ACPI Firmware specification 3.1, zero is also an valid label index. So change code to detect availability of ACPI slot label by checking availaiblity of ACPI _DSM function for PCI label. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-label.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index f12dcd1dc208..0260b14c8d94 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -187,7 +187,6 @@ static const char device_label_dsm_uuid[] = { }; enum acpi_attr_enum { - ACPI_ATTR_NONE = 0, ACPI_ATTR_LABEL_SHOW, ACPI_ATTR_INDEX_SHOW, }; @@ -222,20 +221,16 @@ dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 && tmp[0].type == ACPI_TYPE_INTEGER && tmp[1].type == ACPI_TYPE_STRING) { - len = tmp[0].integer.value; - if (buf) { - /* - * This second string element is optional even when - * this _DSM is implemented; when not implemented, - * this entry must return a null string. - */ - if (attr == ACPI_ATTR_INDEX_SHOW) - scnprintf(buf, PAGE_SIZE, "%llu\n", - tmp->integer.value); - else if (attr == ACPI_ATTR_LABEL_SHOW) - dsm_label_utf16s_to_utf8s(tmp + 1, buf); - len = strlen(buf) > 0 ? strlen(buf) : -1; - } + /* + * The second string element is optional even when + * this _DSM is implemented; when not implemented, + * this entry must return a null string. + */ + if (attr == ACPI_ATTR_INDEX_SHOW) + scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value); + else if (attr == ACPI_ATTR_LABEL_SHOW) + dsm_label_utf16s_to_utf8s(tmp + 1, buf); + len = strlen(buf) > 0 ? strlen(buf) : -1; } ACPI_FREE(obj); @@ -246,7 +241,14 @@ dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) static bool device_has_dsm(struct device *dev) { - return dsm_get_label(dev, NULL, ACPI_ATTR_NONE) > 0; + acpi_handle handle; + + handle = ACPI_HANDLE(dev); + if (!handle) + return false; + + return !!acpi_check_dsm(handle, device_label_dsm_uuid, 0x2, + 1 << DEVICE_LABEL_DSM); } static umode_t -- cgit v1.2.3