[Skiboot] [PATCH] hw/bt.c: Fix message response search

Benjamin Herrenschmidt benh at kernel.crashing.org
Thu Jun 18 10:16:45 AEST 2015


On Wed, 2015-06-17 at 22:12 +1000, Alistair Popple wrote:
> 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))

Ah, you found it !!! Don't forget to also fix the other one we found
yesterday :-)

> 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 at popple.id.au>
> ---
>  hw/bt.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/bt.c b/hw/bt.c
> index 8a9e935..da59b14 100644
> --- a/hw/bt.c
> +++ b/hw/bt.c
> @@ -207,7 +207,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;
> @@ -236,13 +236,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();




More information about the Skiboot mailing list