]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/acpi/property.c
serial: mvebu-uart: Fix to avoid a potential NULL pointer dereference
[mirror_ubuntu-bionic-kernel.git] / drivers / acpi / property.c
index e26ea209b63ef1b8f89a6112de5c983db3f4feee..6c2c53b741e1c80ba3002b140b4cddd23954cf79 100644 (file)
@@ -24,11 +24,23 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data,
                                        acpi_object_type type,
                                        const union acpi_object **obj);
 
-/* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
-static const guid_t prp_guid =
+/*
+ * The GUIDs here are made equivalent to each other in order to avoid extra
+ * complexity in the properties handling code, with the caveat that the
+ * kernel will accept certain combinations of GUID and properties that are
+ * not defined without a warning. For instance if any of the properties
+ * from different GUID appear in a property list of another, it will be
+ * accepted by the kernel. Firmware validation tools should catch these.
+ */
+static const guid_t prp_guids[] = {
+       /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
        GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c,
-                 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01);
-/* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
+                 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01),
+       /* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */
+       GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3,
+                 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89),
+};
+
 static const guid_t ads_guid =
        GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6,
                  0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b);
@@ -56,6 +68,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
        dn->name = link->package.elements[0].string.pointer;
        dn->fwnode.ops = &acpi_data_fwnode_ops;
        dn->parent = parent;
+       INIT_LIST_HEAD(&dn->data.properties);
        INIT_LIST_HEAD(&dn->data.subnodes);
 
        result = acpi_extract_properties(desc, &dn->data);
@@ -288,6 +301,35 @@ static void acpi_init_of_compatible(struct acpi_device *adev)
        adev->flags.of_compatible_ok = 1;
 }
 
+static bool acpi_is_property_guid(const guid_t *guid)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(prp_guids); i++) {
+               if (guid_equal(guid, &prp_guids[i]))
+                       return true;
+       }
+
+       return false;
+}
+
+struct acpi_device_properties *
+acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
+                   const union acpi_object *properties)
+{
+       struct acpi_device_properties *props;
+
+       props = kzalloc(sizeof(*props), GFP_KERNEL);
+       if (props) {
+               INIT_LIST_HEAD(&props->list);
+               props->guid = guid;
+               props->properties = properties;
+               list_add_tail(&props->list, &data->properties);
+       }
+
+       return props;
+}
+
 static bool acpi_extract_properties(const union acpi_object *desc,
                                    struct acpi_device_data *data)
 {
@@ -312,7 +354,7 @@ static bool acpi_extract_properties(const union acpi_object *desc,
                    properties->type != ACPI_TYPE_PACKAGE)
                        break;
 
-               if (!guid_equal((guid_t *)guid->buffer.pointer, &prp_guid))
+               if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer))
                        continue;
 
                /*
@@ -320,13 +362,13 @@ static bool acpi_extract_properties(const union acpi_object *desc,
                 * package immediately following it.
                 */
                if (!acpi_properties_format_valid(properties))
-                       break;
+                       continue;
 
-               data->properties = properties;
-               return true;
+               acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer,
+                                   properties);
        }
 
-       return false;
+       return !list_empty(&data->properties);
 }
 
 void acpi_init_properties(struct acpi_device *adev)
@@ -336,6 +378,7 @@ void acpi_init_properties(struct acpi_device *adev)
        acpi_status status;
        bool acpi_of = false;
 
+       INIT_LIST_HEAD(&adev->data.properties);
        INIT_LIST_HEAD(&adev->data.subnodes);
 
        if (!adev->handle)
@@ -398,11 +441,16 @@ static void acpi_destroy_nondev_subnodes(struct list_head *list)
 
 void acpi_free_properties(struct acpi_device *adev)
 {
+       struct acpi_device_properties *props, *tmp;
+
        acpi_destroy_nondev_subnodes(&adev->data.subnodes);
        ACPI_FREE((void *)adev->data.pointer);
        adev->data.of_compatible = NULL;
        adev->data.pointer = NULL;
-       adev->data.properties = NULL;
+       list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
+               list_del(&props->list);
+               kfree(props);
+       }
 }
 
 /**
@@ -427,32 +475,37 @@ static int acpi_data_get_property(const struct acpi_device_data *data,
                                  const char *name, acpi_object_type type,
                                  const union acpi_object **obj)
 {
-       const union acpi_object *properties;
-       int i;
+       const struct acpi_device_properties *props;
 
        if (!data || !name)
                return -EINVAL;
 
-       if (!data->pointer || !data->properties)
+       if (!data->pointer || list_empty(&data->properties))
                return -EINVAL;
 
-       properties = data->properties;
-       for (i = 0; i < properties->package.count; i++) {
-               const union acpi_object *propname, *propvalue;
-               const union acpi_object *property;
+       list_for_each_entry(props, &data->properties, list) {
+               const union acpi_object *properties;
+               unsigned int i;
 
-               property = &properties->package.elements[i];
+               properties = props->properties;
+               for (i = 0; i < properties->package.count; i++) {
+                       const union acpi_object *propname, *propvalue;
+                       const union acpi_object *property;
 
-               propname = &property->package.elements[0];
-               propvalue = &property->package.elements[1];
+                       property = &properties->package.elements[i];
 
-               if (!strcmp(name, propname->string.pointer)) {
-                       if (type != ACPI_TYPE_ANY && propvalue->type != type)
-                               return -EPROTO;
-                       if (obj)
-                               *obj = propvalue;
+                       propname = &property->package.elements[0];
+                       propvalue = &property->package.elements[1];
 
-                       return 0;
+                       if (!strcmp(name, propname->string.pointer)) {
+                               if (type != ACPI_TYPE_ANY &&
+                                   propvalue->type != type)
+                                       return -EPROTO;
+                               if (obj)
+                                       *obj = propvalue;
+
+                               return 0;
+                       }
                }
        }
        return -EINVAL;