[PATCH 4.4 104/104] ipmi:ssif: Fix handling of multi-part return messages

From: Greg Kroah-Hartman
Date: Thu Jan 24 2019 - 14:28:42 EST


4.4-stable review patch. If anyone has any objections, please let me know.

------------------

From: Corey Minyard <cminyard@xxxxxxxxxx>

commit 7d6380cd40f7993f75c4bde5b36f6019237e8719 upstream.

The block number was not being compared right, it was off by one
when checking the response.

Some statistics wouldn't be incremented properly in some cases.

Check to see if that middle-part messages always have 31 bytes of
data.

Signed-off-by: Corey Minyard <cminyard@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx # 4.4
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/char/ipmi/ipmi_ssif.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)

--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -637,8 +637,9 @@ static void msg_done_handler(struct ssif

/* Remove the multi-part read marker. */
len -= 2;
+ data += 2;
for (i = 0; i < len; i++)
- ssif_info->data[i] = data[i+2];
+ ssif_info->data[i] = data[i];
ssif_info->multi_len = len;
ssif_info->multi_pos = 1;

@@ -666,8 +667,19 @@ static void msg_done_handler(struct ssif
}

blocknum = data[0];
+ len--;
+ data++;
+
+ if (blocknum != 0xff && len != 31) {
+ /* All blocks but the last must have 31 data bytes. */
+ result = -EIO;
+ if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
+ pr_info("Received middle message <31\n");

- if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) {
+ goto continue_op;
+ }
+
+ if (ssif_info->multi_len + len > IPMI_MAX_MSG_LENGTH) {
/* Received message too big, abort the operation. */
result = -E2BIG;
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
@@ -676,16 +688,14 @@ static void msg_done_handler(struct ssif
goto continue_op;
}

- /* Remove the blocknum from the data. */
- len--;
for (i = 0; i < len; i++)
- ssif_info->data[i + ssif_info->multi_len] = data[i + 1];
+ ssif_info->data[i + ssif_info->multi_len] = data[i];
ssif_info->multi_len += len;
if (blocknum == 0xff) {
/* End of read */
len = ssif_info->multi_len;
data = ssif_info->data;
- } else if (blocknum + 1 != ssif_info->multi_pos) {
+ } else if (blocknum != ssif_info->multi_pos) {
/*
* Out of sequence block, just abort. Block
* numbers start at zero for the second block,
@@ -713,6 +723,7 @@ static void msg_done_handler(struct ssif
}
}

+ continue_op:
if (result < 0) {
ssif_inc_stat(ssif_info, receive_errors);
} else {
@@ -720,8 +731,6 @@ static void msg_done_handler(struct ssif
ssif_inc_stat(ssif_info, received_message_parts);
}

-
- continue_op:
if (ssif_info->ssif_debug & SSIF_DEBUG_STATE)
pr_info(PFX "DONE 1: state = %d, result=%d.\n",
ssif_info->ssif_state, result);