amdgpu_acpi_vfct_bios() fetches the VFCT table with acpi_get_table()
but never releases it. acpi_get_table() takes a reference on the
table (incrementing its validation_count and mapping it on the 0->1
transition); without a paired acpi_put_table() the mapping is leaked
on every call, whether or not a matching VBIOS image is found.

Route all exit paths after the table is acquired through a common
acpi_put_table(). The VBIOS image is copied out with kmemdup() before
the table is released, so it remains valid for the caller.

Signed-off-by: Mario Limonciello <[email protected]>
---
Cc: Oz Tiram <[email protected]>
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index d8fd047295d9d..bf6df87e0bafd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -423,13 +423,14 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device 
*adev)
        acpi_size tbl_size;
        UEFI_ACPI_VFCT *vfct;
        unsigned int offset;
+       bool r = false;
 
        if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
                return false;
        tbl_size = hdr->length;
        if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
                dev_info(adev->dev, "ACPI VFCT table present but broken (too 
short #1),skipping\n");
-               return false;
+               goto out;
        }
 
        vfct = (UEFI_ACPI_VFCT *)hdr;
@@ -442,13 +443,13 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device 
*adev)
                offset += sizeof(VFCT_IMAGE_HEADER);
                if (offset > tbl_size) {
                        dev_info(adev->dev, "ACPI VFCT image header 
truncated,skipping\n");
-                       return false;
+                       goto out;
                }
 
                offset += vhdr->ImageLength;
                if (offset > tbl_size) {
                        dev_info(adev->dev, "ACPI VFCT image 
truncated,skipping\n");
-                       return false;
+                       goto out;
                }
 
                if (vhdr->ImageLength &&
@@ -459,15 +460,19 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device 
*adev)
 
                        if (!check_atom_bios(adev, vhdr->ImageLength)) {
                                amdgpu_bios_release(adev);
-                               return false;
+                               goto out;
                        }
                        adev->bios_size = vhdr->ImageLength;
-                       return true;
+                       r = true;
+                       goto out;
                }
        }
 
        dev_info(adev->dev, "ACPI VFCT table present but broken (too short 
#2),skipping\n");
-       return false;
+
+out:
+       acpi_put_table(hdr);
+       return r;
 }
 #else
 static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
-- 
2.43.0

Reply via email to