Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Kristen Accardi and committed by
Linus Torvalds
593ee207 d66fd908

+35 -25
+35 -25
drivers/pci/pci-acpi.c
··· 33 33 acpi_status status; 34 34 struct acpi_object_list input; 35 35 union acpi_object in_params[4]; 36 - struct acpi_buffer output; 37 - union acpi_object out_obj; 36 + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 37 + union acpi_object *out_obj; 38 38 u32 osc_dw0; 39 39 40 - /* Setting up output buffer */ 41 - output.length = sizeof(out_obj) + 3*sizeof(u32); 42 - output.pointer = &out_obj; 43 40 44 41 /* Setting up input parameters */ 45 42 input.count = 4; ··· 58 61 "Evaluate _OSC Set fails. Status = 0x%04x\n", status); 59 62 return status; 60 63 } 61 - if (out_obj.type != ACPI_TYPE_BUFFER) { 64 + out_obj = output.pointer; 65 + 66 + if (out_obj->type != ACPI_TYPE_BUFFER) { 62 67 printk(KERN_DEBUG 63 68 "Evaluate _OSC returns wrong type\n"); 64 - return AE_TYPE; 69 + status = AE_TYPE; 70 + goto query_osc_out; 65 71 } 66 - osc_dw0 = *((u32 *) out_obj.buffer.pointer); 72 + osc_dw0 = *((u32 *) out_obj->buffer.pointer); 67 73 if (osc_dw0) { 68 74 if (osc_dw0 & OSC_REQUEST_ERROR) 69 75 printk(KERN_DEBUG "_OSC request fails\n"); ··· 76 76 printk(KERN_DEBUG "_OSC invalid revision\n"); 77 77 if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { 78 78 /* Update Global Control Set */ 79 - global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8)); 80 - return AE_OK; 79 + global_ctrlsets = *((u32 *)(out_obj->buffer.pointer+8)); 80 + status = AE_OK; 81 + goto query_osc_out; 81 82 } 82 - return AE_ERROR; 83 + status = AE_ERROR; 84 + goto query_osc_out; 83 85 } 84 86 85 87 /* Update Global Control Set */ 86 - global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8)); 87 - return AE_OK; 88 + global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8)); 89 + status = AE_OK; 90 + 91 + query_osc_out: 92 + kfree(output.pointer); 93 + return status; 88 94 } 89 95 90 96 ··· 102 96 acpi_status status; 103 97 struct acpi_object_list input; 104 98 union acpi_object in_params[4]; 105 - struct acpi_buffer output; 106 - union acpi_object out_obj; 99 + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 100 + union acpi_object *out_obj; 107 101 u32 osc_dw0; 108 102 109 - /* Setting up output buffer */ 110 - output.length = sizeof(out_obj) + 3*sizeof(u32); 111 - output.pointer = &out_obj; 112 - 113 103 /* Setting up input parameters */ 114 104 input.count = 4; 115 105 input.pointer = in_params; ··· 126 124 "Evaluate _OSC Set fails. Status = 0x%04x\n", status); 127 125 return status; 128 126 } 129 - if (out_obj.type != ACPI_TYPE_BUFFER) { 127 + out_obj = output.pointer; 128 + if (out_obj->type != ACPI_TYPE_BUFFER) { 130 129 printk(KERN_DEBUG 131 130 "Evaluate _OSC returns wrong type\n"); 132 - return AE_TYPE; 131 + status = AE_TYPE; 132 + goto run_osc_out; 133 133 } 134 - osc_dw0 = *((u32 *) out_obj.buffer.pointer); 134 + osc_dw0 = *((u32 *) out_obj->buffer.pointer); 135 135 if (osc_dw0) { 136 136 if (osc_dw0 & OSC_REQUEST_ERROR) 137 137 printk(KERN_DEBUG "_OSC request fails\n"); ··· 143 139 printk(KERN_DEBUG "_OSC invalid revision\n"); 144 140 if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { 145 141 printk(KERN_DEBUG "_OSC FW not grant req. control\n"); 146 - return AE_SUPPORT; 142 + status = AE_SUPPORT; 143 + goto run_osc_out; 147 144 } 148 - return AE_ERROR; 145 + status = AE_ERROR; 146 + goto run_osc_out; 149 147 } 150 - return AE_OK; 148 + status = AE_OK; 149 + 150 + run_osc_out: 151 + kfree(output.pointer); 152 + return status; 151 153 } 152 154 153 155 /**