[PATCH] pci: correctly allocate return buffers for osc calls

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>
This commit is contained in:
Kristen Accardi 2006-05-20 15:00:08 -07:00 committed by Linus Torvalds
parent d66fd908ac
commit 593ee20766
1 changed files with 35 additions and 25 deletions

View File

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