aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2015-06-17 22:12:40 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-06-18 14:41:50 +1000
commit89b588267fe9233d6bdb26fa8671f41f79fc690b (patch)
treeb29e5328541dcd6409c6b5cf6e50f1aae8b686f6 /hw
parente6f54808bfada9d4f8a42084463110c1f9fcd348 (diff)
downloadskiboot-89b588267fe9233d6bdb26fa8671f41f79fc690b.zip
skiboot-89b588267fe9233d6bdb26fa8671f41f79fc690b.tar.gz
skiboot-89b588267fe9233d6bdb26fa8671f41f79fc690b.tar.bz2
hw/bt.c: Fix message response search
bt_get_resp() uses the sequence number to locate the outstanding message by searching the queue with list_for_each(...). The check to see if a message was found in the queue is: if (!bt_msg || (bt_msg->seq != seq)) However this check is incorrect. list_for_each(...) does not set bt_msg to NULL at the end of the loop, nor does it set it to the last element in the list. Rather it ends up pointing at an offset from the list_head. Therefore bt_msg is never equal to NULL and the first half of this condition is always false. However the second condition is almost always true as sequence numbers are constantly increasing and unlikely to match whatever bt_msg->seq ends up pointing to, but in rare circumstances it is possible for bt_msg->seq to equal seq and hence the overall expression can evaluate to false. This leads to bt_msg being used as a valid message pointer even though it points to an incorrect address, typically causing a xstop due to an invalid address access when ipmi_cmd_done(...) attempts to call the callbacks. Signed-off-by: Alistair Popple <alistair@popple.id.au> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/bt.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/hw/bt.c b/hw/bt.c
index 8bb44cd..8df31a3 100644
--- a/hw/bt.c
+++ b/hw/bt.c
@@ -214,7 +214,7 @@ static void bt_flush_msg(void)
static void bt_get_resp(void)
{
int i;
- struct bt_msg *bt_msg;
+ struct bt_msg *tmp_bt_msg, *bt_msg = NULL;
struct ipmi_msg *ipmi_msg;
uint8_t resp_len, netfn, seq, cmd;
uint8_t cc = IPMI_CC_NO_ERROR;
@@ -243,13 +243,14 @@ static void bt_get_resp(void)
cc = bt_inb(BT_HOST2BMC);
/* Find the corresponding messasge */
- list_for_each(&bt.msgq, bt_msg, link) {
- if (bt_msg->seq == seq) {
+ list_for_each(&bt.msgq, tmp_bt_msg, link) {
+ if (tmp_bt_msg->seq == seq) {
+ bt_msg = tmp_bt_msg;
break;
}
}
- if (!bt_msg || (bt_msg->seq != seq)) {
+ if (!bt_msg) {
/* A response to a message we no longer care about. */
prlog(PR_INFO, "BT: Nobody cared about a response to an BT/IPMI message\n");
bt_flush_msg();