From patchwork Fri Jul 4 07:03:11 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Roszko X-Patchwork-Id: 4478221 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 10593BEEAA for ; Fri, 4 Jul 2014 07:06:47 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 445FA203E3 for ; Fri, 4 Jul 2014 07:06:46 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 63568201F5 for ; Fri, 4 Jul 2014 07:06:45 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X2xXp-0006GI-JD; Fri, 04 Jul 2014 07:04:29 +0000 Received: from mail-qc0-x22f.google.com ([2607:f8b0:400d:c01::22f]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X2xXn-0006Bn-31 for linux-arm-kernel@lists.infradead.org; Fri, 04 Jul 2014 07:04:27 +0000 Received: by mail-qc0-f175.google.com with SMTP id i8so1158022qcq.34 for ; Fri, 04 Jul 2014 00:04:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=LTUe9QqNJQtqyu9MO/WoiGUNjQX9KIVzxUU3ftEY5Wc=; b=PunXtwTfhuRBkgYueTOXQSAPhSJfyDJxvgZid6i/TqxAQ+UI+6pBREMrLPguG9go3w 61Byu7zMSJsznV/IkeiILyUMUtL+l+5ZIqfKaGFOqJXAT5hyTRUjnmzl+twOm44v6MCd aLGr45kfC+DCjhslHqd9rJF+dJPoh4P4UOgaPFDEfMBx1mTBq2gLV95Xo/HwQlX/HHBt JMoz6xmG31r1dGl8R9nW4IDhlWauK7Dwd5wXO3rF5zY778eEmTvRJNOvOpcTY0plUd76 4b6Kx3Vn6hGzgdlN5sSZ/h1IzIFVbq1pWcEUx7FU2B6b0Zr64mYkP49+2JGgAX2HzqdR PDUw== X-Received: by 10.224.112.131 with SMTP id w3mr16190201qap.68.1404457443721; Fri, 04 Jul 2014 00:04:03 -0700 (PDT) Received: from localhost.localdomain (ool-2f142fe1.dyn.optonline.net. [47.20.47.225]) by mx.google.com with ESMTPSA id y10sm54077089qal.32.2014.07.04.00.04.02 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 04 Jul 2014 00:04:03 -0700 (PDT) From: Marek Roszko To: ludovic.desroches@atmel.com Subject: [PATCH] i2c:at91: add bound checking on smbus block length bytes Date: Fri, 4 Jul 2014 03:03:11 -0400 Message-Id: <1404457391-22330-1-git-send-email-mark.roszko@gmail.com> X-Mailer: git-send-email 1.7.10.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140704_000427_231045_A37B100A X-CRM114-Status: GOOD ( 15.48 ) X-Spam-Score: -0.1 (/) Cc: Marek Roszko , nicolas.ferre@atmel.com, linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, wsa@the-dreams.de X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The driver was not bound checking the recieved length byte to ensure it was less than the buffer size that is allocated for smbus blocks. This resulted in buffer overflows whenever an invalid byte was recieved. It also failed to ensure the byte count was not zero. If it recieved 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 battery. Signed-off-by: Marek Roszko Acked-By: Ludovic Desroches --- drivers/i2c/busses/i2c-at91.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index e95f9ba..ec4ff33 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -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);