From patchwork Mon Feb 1 22:39:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Henderson X-Patchwork-Id: 8184261 Return-Path: X-Original-To: patchwork-linux-spi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 52C2E9F3CD for ; Mon, 1 Feb 2016 22:40:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 728A8202AE for ; Mon, 1 Feb 2016 22:40:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 79A482025A for ; Mon, 1 Feb 2016 22:40:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753750AbcBAWk5 (ORCPT ); Mon, 1 Feb 2016 17:40:57 -0500 Received: from exsmtp01.microchip.com ([198.175.253.37]:55149 "EHLO email.microchip.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753644AbcBAWk4 (ORCPT ); Mon, 1 Feb 2016 17:40:56 -0500 X-Greylist: delayed 307 seconds by postgrey-1.27 at vger.kernel.org; Mon, 01 Feb 2016 17:40:56 EST Received: from mx.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.181.6; Mon, 1 Feb 2016 15:35:47 -0700 Received: by mx.microchip.com (sSMTP sendmail emulation); Mon, 01 Feb 2016 15:39:37 -0700 From: Joshua Henderson To: CC: Purna Chandra Mandal , Joshua Henderson , Mark Brown , Subject: [PATCH] spi: Fix incomplete handling of SPI_MASTER_MUST_RX/_MUST_TX Date: Mon, 1 Feb 2016 15:39:23 -0700 Message-ID: <1454366363-10564-1-git-send-email-joshua.henderson@microchip.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 From: Purna Chandra Mandal There is a BUG in the way SPI_MASTER_MUST_RX/TX is implemented which can create a kernel crash. To simplify design spi driver can specify *_MUST_RX during registration. In these cases spi core do allocate & assign dummy RX buffer (of right size) with the transfer if the transfer has NULL 'rx_buf'; at later point the dummy buffer is free'd when the spi transfer (actually message containing the transfer) is handled by respective master driver and no other spi messages pending with the spi core. This is where BUG is hiding! (1) spi core assigns dummy_rx buffer to transfer.rx_buf member and (2) passes it to lower layer for handling. and lower layer completed the transfer/message in due time. (3) spi core deletes the buffer if no other requests pending, but 'transfer.rx_buf' continues to hold *stale* dummy buffer pointer. (4) If spi client driver (like mmc_spi) reuses the same transfer structure and don't touch .rx_buf to NULL mmc_spi doesn't reset the ptr unless data transfer direction changes in future transaction(s). spi core will skip assigning new dummy buffer and underlying master driver will treat .rx_buf as legitimate ptr. This will result into memory corruption due to usage of free'd ptr. Signed-off-by: Purna Chandra Mandal Signed-off-by: Joshua Henderson --- drivers/spi/spi.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 47eff80..deabd6f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -819,6 +819,15 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) struct spi_transfer *xfer; struct device *tx_dev, *rx_dev; + if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (xfer->rx_buf == master->dummy_rx) + xfer->rx_buf = NULL; + if (xfer->tx_buf == master->dummy_tx) + xfer->tx_buf = NULL; + } + } + if (!master->cur_msg_mapped || !master->can_dma) return 0; @@ -1264,12 +1273,11 @@ void spi_finalize_current_message(struct spi_master *master) unsigned long flags; int ret; + spi_unmap_msg(master, master->cur_msg); spin_lock_irqsave(&master->queue_lock, flags); mesg = master->cur_msg; spin_unlock_irqrestore(&master->queue_lock, flags); - spi_unmap_msg(master, mesg); - if (master->cur_msg_prepared && master->unprepare_message) { ret = master->unprepare_message(master, mesg); if (ret) {