[PATCH] pci: correctly allocate return buffers for osc calls
authorKristen Accardi <kristen.c.accardi@intel.com>
Sat, 20 May 2006 22:00:08 +0000 (15:00 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sun, 21 May 2006 19:59:18 +0000 (12:59 -0700)
The OSC set and query functions do not allocate enough space for return
values, and set the output buffer length to a false, too large value.  This
causes the acpi-ca code to assume that the output buffer is larger than it
actually is, and overwrite memory when copying acpi return buffers into
this caller provided buffer.  In some cases this can cause kernel oops if
the memory that is overwritten is a pointer.  This patch will change these
calls to use a dynamically allocated output buffer, thus allowing the
acpi-ca code to decide how much space is needed.

Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Cc: "Brown, Len" <len.brown@intel.com>
Cc: "Yu, Luming" <luming.yu@intel.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/pci/pci-acpi.c

index 6917c6cb091287a407a6274fa7ebdd382237bed5..c2ecae5ff0c17623917f0b365d7fd9e278be90a2 100644 (file)
@@ -33,13 +33,10 @@ acpi_query_osc (
        acpi_status             status;
        struct acpi_object_list input;
        union acpi_object       in_params[4];
-       struct acpi_buffer      output;
-       union acpi_object       out_obj;        
+       struct acpi_buffer      output = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object       *out_obj;
        u32                     osc_dw0;
 
-       /* Setting up output buffer */
-       output.length = sizeof(out_obj) + 3*sizeof(u32);  
-       output.pointer = &out_obj;
        
        /* Setting up input parameters */
        input.count = 4;
@@ -61,12 +58,15 @@ acpi_query_osc (
                        "Evaluate _OSC Set fails. Status = 0x%04x\n", status);
                return status;
        }
-       if (out_obj.type != ACPI_TYPE_BUFFER) {
+       out_obj = output.pointer;
+
+       if (out_obj->type != ACPI_TYPE_BUFFER) {
                printk(KERN_DEBUG  
                        "Evaluate _OSC returns wrong type\n");
-               return AE_TYPE;
+               status = AE_TYPE;
+               goto query_osc_out;
        }
-       osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+       osc_dw0 = *((u32 *) out_obj->buffer.pointer);
        if (osc_dw0) {
                if (osc_dw0 & OSC_REQUEST_ERROR)
                        printk(KERN_DEBUG "_OSC request fails\n"); 
@@ -76,15 +76,21 @@ acpi_query_osc (
                        printk(KERN_DEBUG "_OSC invalid revision\n"); 
                if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
                        /* Update Global Control Set */
-                       global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8));
-                       return AE_OK;
+                       global_ctrlsets = *((u32 *)(out_obj->buffer.pointer+8));
+                       status = AE_OK;
+                       goto query_osc_out;
                }
-               return AE_ERROR;
+               status = AE_ERROR;
+               goto query_osc_out;
        }
 
        /* Update Global Control Set */
-       global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8));
-       return AE_OK;
+       global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8));
+       status = AE_OK;
+
+query_osc_out:
+       kfree(output.pointer);
+       return status;
 }
 
 
@@ -96,14 +102,10 @@ acpi_run_osc (
        acpi_status             status;
        struct acpi_object_list input;
        union acpi_object       in_params[4];
-       struct acpi_buffer      output;
-       union acpi_object       out_obj;        
+       struct acpi_buffer      output = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object       *out_obj;
        u32                     osc_dw0;
 
-       /* Setting up output buffer */
-       output.length = sizeof(out_obj) + 3*sizeof(u32);  
-       output.pointer = &out_obj;
-       
        /* Setting up input parameters */
        input.count = 4;
        input.pointer = in_params;
@@ -124,12 +126,14 @@ acpi_run_osc (
                        "Evaluate _OSC Set fails. Status = 0x%04x\n", status);
                return status;
        }
-       if (out_obj.type != ACPI_TYPE_BUFFER) {
+       out_obj = output.pointer;
+       if (out_obj->type != ACPI_TYPE_BUFFER) {
                printk(KERN_DEBUG  
                        "Evaluate _OSC returns wrong type\n");
-               return AE_TYPE;
+               status = AE_TYPE;
+               goto run_osc_out;
        }
-       osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+       osc_dw0 = *((u32 *) out_obj->buffer.pointer);
        if (osc_dw0) {
                if (osc_dw0 & OSC_REQUEST_ERROR)
                        printk(KERN_DEBUG "_OSC request fails\n"); 
@@ -139,11 +143,17 @@ acpi_run_osc (
                        printk(KERN_DEBUG "_OSC invalid revision\n"); 
                if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
                        printk(KERN_DEBUG "_OSC FW not grant req. control\n");
-                       return AE_SUPPORT;
+                       status = AE_SUPPORT;
+                       goto run_osc_out;
                }
-               return AE_ERROR;
+               status = AE_ERROR;
+               goto run_osc_out;
        }
-       return AE_OK;
+       status = AE_OK;
+
+run_osc_out:
+       kfree(output.pointer);
+       return status;
 }
 
 /**