i2c:at91: add bound checking on SMBus block length bytes
Subsystems (2)
PATCH v2 1/1 i2c:at91: add bound checking on SMBus block length bytes
The driver was not bound checking the received length byte to ensure it was within the the buffer size that is allocated for SMBus blocks. This resulted in buffer overflows whenever an invalid length byte was received.
It also failed to ensure the length byte was not zero. If it received zero, it would end up in an infinite loop as the at91_twi_read_next_byte function returned immediately without allowing RHR to be read to clear the RXRDY interrupt.
Tested agaisnt a SMBus compliant battery.
---
Change from v1:
fixed typo in commit message
reworded message slightly to be specifically say length byte
drivers/i2c/busses/i2c-at91.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
drivers/i2c/busses/i2c-at91.c +24 -4
@@ -101,6 +101,7 @@ struct at91_twi_dev {unsigned twi_cwgr_reg;struct at91_twi_pdata *pdata;bool use_dma; +bool recv_len_abort;struct at91_twi_dma dma; };
@@ -267,12 +268,24 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) *dev->buf =at91_twi_read (dev,AT91_TWI_RHR ) &0xff ; --dev->buf_len; +/* return if aborting, we only needed to read RHR to clear RXRDY*/ +if (dev->recv_len_abort) +return ; +/* handle I2C_SMBUS_BLOCK_DATA */ if (unlikely (dev->msg->flags &I2C_M_RECV_LEN )) { - dev->msg->flags &= ~I2C_M_RECV_LEN ; - dev->buf_len += *dev->buf; - dev->msg->len = dev->buf_len +1 ; -dev_dbg (dev->dev,"received block length %d\n" , dev->buf_len); +/* ensure length byte is a valid value */ +if (*dev->buf <=I2C_SMBUS_BLOCK_MAX && *dev->buf >0 ) { + dev->msg->flags &= ~I2C_M_RECV_LEN ; + dev->buf_len += *dev->buf; + dev->msg->len = dev->buf_len +1 ; +dev_dbg (dev->dev,"received block length %d\n" , + dev->buf_len); + }else { +/* abort and send the stop by reading one more byte */ + dev->recv_len_abort = true; + dev->buf_len =1 ; + } }/* send stop if second but last byte has been read */
@@ -444,6 +457,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) ret = -EIO ; goto error; } +if (dev->recv_len_abort) { +dev_err (dev->dev,"invalid smbus block length recvd\n" ); + ret = -EPROTO ; + goto error; + } +dev_dbg (dev->dev,"transfer complete\n" );return 0 ;
@@ -500,6 +519,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) dev->buf_len = m_start->len; dev->buf = m_start->buf; dev->msg = m_start; + dev->recv_len_abort = false; ret =at91_do_twi_transfer (dev);
Signature · 1 line
1.7.10.4
PATCH v2 1/1 i2c:at91: add bound checking on SMBus block length bytes
Hi Wolfram,
Could you take this patch into your tree?
Thanks
Regards
Ludovic
Quoted 89 lines · Marek Roszko
The driver was not bound checking the received length byte to ensure it was within the the buffer size that is allocated for SMBus blocks. This resulted in buffer overflows whenever an invalid length byte was received.
It also failed to ensure the length byte was not zero. If it received zero, it would end up in an infinite loop as theat91_twi_read_next_bytefunction returned immediately without allowing RHR to be read to clear the RXRDY interrupt.Tested agaisnt a SMBus compliant battery.
Signed-off-by Marek Roszko <[email protected]>---
Change from v1:
fixed typo in commit message
reworded message slightly to be specifically say length bytedrivers/i2c/busses/i2c-at91.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)drivers/i2c/busses/i2c-at91.c +24
-4@@ -101,6 +101,7 @@ struct at91_twi_dev {unsigned twi_cwgr_reg;struct at91_twi_pdata *pdata;bool use_dma; +bool recv_len_abort;struct at91_twi_dma dma; };@@ -267,12 +268,24 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) *dev->buf =at91_twi_read (dev,AT91_TWI_RHR ) &0xff ; --dev->buf_len; +/* return if aborting, we only needed to read RHR to clear RXRDY*/ +if (dev->recv_len_abort) +return ; +/* handle I2C_SMBUS_BLOCK_DATA */ if (unlikely (dev->msg->flags &I2C_M_RECV_LEN )) { - dev->msg->flags &= ~I2C_M_RECV_LEN ; - dev->buf_len += *dev->buf; - dev->msg->len = dev->buf_len +1 ; -dev_dbg (dev->dev,"received block length %d\n" , dev->buf_len); +/* ensure length byte is a valid value */ +if (*dev->buf <=I2C_SMBUS_BLOCK_MAX && *dev->buf >0 ) { + dev->msg->flags &= ~I2C_M_RECV_LEN ; + dev->buf_len += *dev->buf; + dev->msg->len = dev->buf_len +1 ; +dev_dbg (dev->dev,"received block length %d\n" , + dev->buf_len); + }else { +/* abort and send the stop by reading one more byte */ + dev->recv_len_abort = true; + dev->buf_len =1 ; + } }/* send stop if second but last byte has been read */ @@ -444,6 +457,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) ret = -EIO ; goto error; } +if (dev->recv_len_abort) { +dev_err (dev->dev,"invalid smbus block length recvd\n" ); + ret = -EPROTO ; + goto error; + } +dev_dbg (dev->dev,"transfer complete\n" );return 0 ;@@ -500,6 +519,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) dev->buf_len = m_start->len; dev->buf = m_start->buf; dev->msg = m_start; + dev->recv_len_abort = false; ret =at91_do_twi_transfer (dev);Signature · 7 lines
1.7.10.4 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 1/1 i2c:at91: add bound checking on SMBus block length bytes
Hi Ludovic,
Wolfram took in the patch quietly awhile back. It's in the 3.17 kernel and backported to some of the older trees.
https://github.com/torvalds/linux/commit/75b81f339c6af43f6f4a1b3eabe0603321dade65
Regards,
Mark
PATCH v2 1/1 i2c:at91: add bound checking on SMBus block length bytes
Hi,
Quoted 5 lines · Mark Roszko
Hi Ludovic,
Wolfram took in the patch quietly awhile back. It's in the 3.17 kernel and backported to some of the older trees.
https://github.com/torvalds/linux/commit/75b81f339c6af43f6f4a1b3eabe0603321dade65
Great, sorry for the noise so. It seems I have checked it from a wrong branch.
Ludovic
Quoted 7 lines
Regards,
Mark
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 1/1 i2c:at91: add bound checking on SMBus block length bytes
Quoted 7 lines
Quoted 4 lines
Wolfram took in the patch quietly awhile back. It's in the 3.17 kernel and backported to some of the older trees.
https://github.com/torvalds/linux/commit/75b81f339c6af43f6f4a1b3eabe0603321dade65Great, sorry for the noise so. It seems I have checked it from a wrong branch.
Yes, usually I send out mails when applying patches. Dunno why I missed it here.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141027/9cec37aa/attachment.sig>