aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2013-09-13 01:13:30 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-09-30 13:46:11 -0400
commit6b68f03f95e3f0aeea0c47799aecb296276a7cd6 (patch)
treebdb6018d8a6f2a9661c1a2fa0351fe0491b33d27
parent15c03dd4859ab16f9212238f29dd315654aa94f6 (diff)
ACPI / IPMI: Fix potential response buffer overflow
This patch enhances sanity checks on message size to avoid potential buffer overflow. The kernel IPMI message size is IPMI_MAX_MSG_LENGTH(272 bytes) while the ACPI specification defined IPMI message size is 64 bytes. The difference is not handled by the original codes. This may cause crash in the response handling codes. This patch closes this gap and also combines rx_data/tx_data to use single data/len pair since they need not be seperate. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Reviewed-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/acpi_ipmi.c53
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c
index a6977e12d574..7397135702db 100644
--- a/drivers/acpi/acpi_ipmi.c
+++ b/drivers/acpi/acpi_ipmi.c
@@ -52,6 +52,7 @@ MODULE_LICENSE("GPL");
52#define ACPI_IPMI_UNKNOWN 0x07 52#define ACPI_IPMI_UNKNOWN 0x07
53/* the IPMI timeout is 5s */ 53/* the IPMI timeout is 5s */
54#define IPMI_TIMEOUT (5 * HZ) 54#define IPMI_TIMEOUT (5 * HZ)
55#define ACPI_IPMI_MAX_MSG_LENGTH 64
55 56
56struct acpi_ipmi_device { 57struct acpi_ipmi_device {
57 /* the device list attached to driver_data.ipmi_devices */ 58 /* the device list attached to driver_data.ipmi_devices */
@@ -90,11 +91,9 @@ struct acpi_ipmi_msg {
90 struct completion tx_complete; 91 struct completion tx_complete;
91 struct kernel_ipmi_msg tx_message; 92 struct kernel_ipmi_msg tx_message;
92 int msg_done; 93 int msg_done;
93 /* tx data . And copy it from ACPI object buffer */ 94 /* tx/rx data . And copy it from/to ACPI object buffer */
94 u8 tx_data[64]; 95 u8 data[ACPI_IPMI_MAX_MSG_LENGTH];
95 int tx_len; 96 u8 rx_len;
96 u8 rx_data[64];
97 int rx_len;
98 struct acpi_ipmi_device *device; 97 struct acpi_ipmi_device *device;
99}; 98};
100 99
@@ -102,7 +101,7 @@ struct acpi_ipmi_msg {
102struct acpi_ipmi_buffer { 101struct acpi_ipmi_buffer {
103 u8 status; 102 u8 status;
104 u8 length; 103 u8 length;
105 u8 data[64]; 104 u8 data[ACPI_IPMI_MAX_MSG_LENGTH];
106}; 105};
107 106
108static void ipmi_register_bmc(int iface, struct device *dev); 107static void ipmi_register_bmc(int iface, struct device *dev);
@@ -141,7 +140,7 @@ static struct acpi_ipmi_msg *acpi_alloc_ipmi_msg(struct acpi_ipmi_device *ipmi)
141 140
142#define IPMI_OP_RGN_NETFN(offset) ((offset >> 8) & 0xff) 141#define IPMI_OP_RGN_NETFN(offset) ((offset >> 8) & 0xff)
143#define IPMI_OP_RGN_CMD(offset) (offset & 0xff) 142#define IPMI_OP_RGN_CMD(offset) (offset & 0xff)
144static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg, 143static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg,
145 acpi_physical_address address, 144 acpi_physical_address address,
146 acpi_integer *value) 145 acpi_integer *value)
147{ 146{
@@ -157,15 +156,21 @@ static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg,
157 */ 156 */
158 msg->netfn = IPMI_OP_RGN_NETFN(address); 157 msg->netfn = IPMI_OP_RGN_NETFN(address);
159 msg->cmd = IPMI_OP_RGN_CMD(address); 158 msg->cmd = IPMI_OP_RGN_CMD(address);
160 msg->data = tx_msg->tx_data; 159 msg->data = tx_msg->data;
161 /* 160 /*
162 * value is the parameter passed by the IPMI opregion space handler. 161 * value is the parameter passed by the IPMI opregion space handler.
163 * It points to the IPMI request message buffer 162 * It points to the IPMI request message buffer
164 */ 163 */
165 buffer = (struct acpi_ipmi_buffer *)value; 164 buffer = (struct acpi_ipmi_buffer *)value;
166 /* copy the tx message data */ 165 /* copy the tx message data */
166 if (buffer->length > ACPI_IPMI_MAX_MSG_LENGTH) {
167 dev_WARN_ONCE(&tx_msg->device->pnp_dev->dev, true,
168 "Unexpected request (msg len %d).\n",
169 buffer->length);
170 return -EINVAL;
171 }
167 msg->data_len = buffer->length; 172 msg->data_len = buffer->length;
168 memcpy(tx_msg->tx_data, buffer->data, msg->data_len); 173 memcpy(tx_msg->data, buffer->data, msg->data_len);
169 /* 174 /*
170 * now the default type is SYSTEM_INTERFACE and channel type is BMC. 175 * now the default type is SYSTEM_INTERFACE and channel type is BMC.
171 * If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE, 176 * If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE,
@@ -183,6 +188,7 @@ static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg,
183 device->curr_msgid++; 188 device->curr_msgid++;
184 tx_msg->tx_msgid = device->curr_msgid; 189 tx_msg->tx_msgid = device->curr_msgid;
185 spin_unlock_irqrestore(&device->tx_msg_lock, flags); 190 spin_unlock_irqrestore(&device->tx_msg_lock, flags);
191 return 0;
186} 192}
187 193
188static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, 194static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg,
@@ -214,7 +220,7 @@ static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg,
214 */ 220 */
215 buffer->status = ACPI_IPMI_OK; 221 buffer->status = ACPI_IPMI_OK;
216 buffer->length = msg->rx_len; 222 buffer->length = msg->rx_len;
217 memcpy(buffer->data, msg->rx_data, msg->rx_len); 223 memcpy(buffer->data, msg->data, msg->rx_len);
218} 224}
219 225
220static void ipmi_flush_tx_msg(struct acpi_ipmi_device *ipmi) 226static void ipmi_flush_tx_msg(struct acpi_ipmi_device *ipmi)
@@ -250,8 +256,7 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
250 dev_warn(&pnp_dev->dev, "Unexpected response is returned. " 256 dev_warn(&pnp_dev->dev, "Unexpected response is returned. "
251 "returned user %p, expected user %p\n", 257 "returned user %p, expected user %p\n",
252 msg->user, ipmi_device->user_interface); 258 msg->user, ipmi_device->user_interface);
253 ipmi_free_recv_msg(msg); 259 goto out_msg;
254 return;
255 } 260 }
256 spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags); 261 spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
257 list_for_each_entry(tx_msg, &ipmi_device->tx_msg_list, head) { 262 list_for_each_entry(tx_msg, &ipmi_device->tx_msg_list, head) {
@@ -265,17 +270,21 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
265 if (!msg_found) { 270 if (!msg_found) {
266 dev_warn(&pnp_dev->dev, "Unexpected response (msg id %ld) is " 271 dev_warn(&pnp_dev->dev, "Unexpected response (msg id %ld) is "
267 "returned.\n", msg->msgid); 272 "returned.\n", msg->msgid);
268 ipmi_free_recv_msg(msg); 273 goto out_msg;
269 return;
270 } 274 }
271 275
272 if (msg->msg.data_len) { 276 /* copy the response data to Rx_data buffer */
273 /* copy the response data to Rx_data buffer */ 277 if (msg->msg.data_len > ACPI_IPMI_MAX_MSG_LENGTH) {
274 memcpy(tx_msg->rx_data, msg->msg_data, msg->msg.data_len); 278 dev_WARN_ONCE(&pnp_dev->dev, true,
279 "Unexpected response (msg len %d).\n",
280 msg->msg.data_len);
281 } else {
275 tx_msg->rx_len = msg->msg.data_len; 282 tx_msg->rx_len = msg->msg.data_len;
283 memcpy(tx_msg->data, msg->msg.data, tx_msg->rx_len);
276 tx_msg->msg_done = 1; 284 tx_msg->msg_done = 1;
277 } 285 }
278 complete(&tx_msg->tx_complete); 286 complete(&tx_msg->tx_complete);
287out_msg:
279 ipmi_free_recv_msg(msg); 288 ipmi_free_recv_msg(msg);
280}; 289};
281 290
@@ -398,7 +407,10 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
398 if (!tx_msg) 407 if (!tx_msg)
399 return AE_NO_MEMORY; 408 return AE_NO_MEMORY;
400 409
401 acpi_format_ipmi_msg(tx_msg, address, value); 410 if (acpi_format_ipmi_request(tx_msg, address, value) != 0) {
411 status = AE_TYPE;
412 goto out_msg;
413 }
402 spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags); 414 spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
403 list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list); 415 list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list);
404 spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags); 416 spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);
@@ -409,17 +421,18 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
409 NULL, 0, 0, 0); 421 NULL, 0, 0, 0);
410 if (err) { 422 if (err) {
411 status = AE_ERROR; 423 status = AE_ERROR;
412 goto end_label; 424 goto out_list;
413 } 425 }
414 rem_time = wait_for_completion_timeout(&tx_msg->tx_complete, 426 rem_time = wait_for_completion_timeout(&tx_msg->tx_complete,
415 IPMI_TIMEOUT); 427 IPMI_TIMEOUT);
416 acpi_format_ipmi_response(tx_msg, value, rem_time); 428 acpi_format_ipmi_response(tx_msg, value, rem_time);
417 status = AE_OK; 429 status = AE_OK;
418 430
419end_label: 431out_list:
420 spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags); 432 spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
421 list_del(&tx_msg->head); 433 list_del(&tx_msg->head);
422 spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags); 434 spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);
435out_msg:
423 kfree(tx_msg); 436 kfree(tx_msg);
424 return status; 437 return status;
425} 438}