From patchwork Sat Nov 29 21:00:02 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kochetkov X-Patchwork-Id: 416011 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 59999140186 for ; Sun, 30 Nov 2014 08:00:44 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751681AbaK2VAW (ORCPT ); Sat, 29 Nov 2014 16:00:22 -0500 Received: from mail-lb0-f172.google.com ([209.85.217.172]:48894 "EHLO mail-lb0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751799AbaK2VAT (ORCPT ); Sat, 29 Nov 2014 16:00:19 -0500 Received: by mail-lb0-f172.google.com with SMTP id u10so6987382lbd.17 for ; Sat, 29 Nov 2014 13:00:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=N3cZlhHvV4BV0jNWntJi34ifDbZjgPI+SJ0NBOmcDk0=; b=kUNSANJpSUc408KxZmoKvu8rh5cfpBufDBPwjNu6ZZS8S7JpilVw+Jrc7SNoAEx/PA 5VrNYKZb6pdvOIZDF0+H559hYPWJcX/Yy5suQHQKW/SpH+jXDEpz0m9/BHAbrxFkWwiM n0ZL4YgC1+Gc9rBA2DLg7pgsk2sQe/SEj2vB28nuQNexomiX+yo0AmiJAGJppLVIyv9a WEv3VMDN5TVdCzXbIuVT8NlQoFm2/P8JLSMG48J1AIXtVQX+a0UPUWCqCmOVhEKIHfMA FnjtJzqN7Mj6sR9k3kzZIsmzNatnSGvWXA02nvKBub9FBui9Rp5p+o2nwfuEVUU7rHUF Z1IQ== X-Received: by 10.152.43.13 with SMTP id s13mr15778174lal.69.1417294817486; Sat, 29 Nov 2014 13:00:17 -0800 (PST) Received: from localhost.localdomain ([79.165.17.98]) by mx.google.com with ESMTPSA id n4sm3489579lan.39.2014.11.29.13.00.16 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 29 Nov 2014 13:00:16 -0800 (PST) From: Alexander Kochetkov To: Kevin Hilman , Tony Lindgren , Felipe Balbi , Wolfram Sang , Alexander Kochetkov Cc: linux-omap@vger.kernel.org, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC 1/2] i2c: omap: fix buffer overruns during RX/TX data processing Date: Sun, 30 Nov 2014 01:00:02 +0400 Message-Id: <1417294803-14729-2-git-send-email-al.kochet@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1417294803-14729-1-git-send-email-al.kochet@gmail.com> References: <1417294803-14729-1-git-send-email-al.kochet@gmail.com> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org commit dd74548ddece4b9d68e5528287a272fa552c81d0 ("i2c: omap: resize fifos before each message") dropped check for dev->buf_len. As result, data processing loop cause dev->buf overruns for devices with 16-bit data register (omap2420). In the dd74548ddece4b9d68 code, for each loop iteration if the flag OMAP_I2C_FLAG_16BIT_DATA_REG is set (omap2420), dev->buf is incremented twice, and dev->buf_len decremented twice. Also buffer overrun could happen (in theory) due to wrong ISR handling (bug). The commit fix data processing for omap2420 and add guard checks in the data processing loops do disallow accesses to the buffer, when dev->buf_len is zero. Also added warnings to unhide the bug. Found by code review. Signed-off-by: Alexander Kochetkov Fixes: dd74548ddece4b9d68e5528287a272fa552c81d0 "i2c: omap: resize fifos before each message" Reported-by: Tony Lindgren --- drivers/i2c/busses/i2c-omap.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 4563200..e890295 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -938,20 +938,30 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, bool is_rdr) { - u16 w; + u16 w; + + if (unlikely(num_bytes > dev->buf_len)) { + dev_err(dev->dev, "%s interrupt can't receive %u byte(s)\n", + is_rdr ? "RDR" : "RRDY", (num_bytes - dev->buf_len)); + num_bytes = dev->buf_len; + } - while (num_bytes--) { + while (num_bytes) { w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; + num_bytes--; /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - *dev->buf++ = w >> 8; - dev->buf_len--; + if (num_bytes) { + *dev->buf++ = w >> 8; + dev->buf_len--; + num_bytes--; + } } } } @@ -959,19 +969,29 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, bool is_xdr) { - u16 w; + u16 w; + + if (unlikely(num_bytes > dev->buf_len)) { + dev_err(dev->dev, "%s interrupt can't transmit %u byte(s)\n", + is_xdr ? "XDR" : "XRDY", (num_bytes - dev->buf_len)); + num_bytes = dev->buf_len; + } - while (num_bytes--) { + while (num_bytes) { w = *dev->buf++; dev->buf_len--; + num_bytes--; /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - w |= *dev->buf++ << 8; - dev->buf_len--; + if (num_bytes) { + w |= *dev->buf++ << 8; + dev->buf_len--; + num_bytes--; + } } if (dev->errata & I2C_OMAP_ERRATA_I462) {