From patchwork Mon Dec 10 15:28:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Biju Das X-Patchwork-Id: 10721449 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D90076C5 for ; Mon, 10 Dec 2018 15:37:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C60D629B87 for ; Mon, 10 Dec 2018 15:37:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BA5372A8CF; Mon, 10 Dec 2018 15:37:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4CF412A850 for ; Mon, 10 Dec 2018 15:37:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728102AbeLJPhE (ORCPT ); Mon, 10 Dec 2018 10:37:04 -0500 Received: from relmlor1.renesas.com ([210.160.252.171]:56574 "EHLO relmlie5.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727313AbeLJPhE (ORCPT ); Mon, 10 Dec 2018 10:37:04 -0500 X-IronPort-AV: E=Sophos;i="5.56,338,1539615600"; d="scan'208";a="2433823" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 11 Dec 2018 00:37:02 +0900 Received: from be1yocto.ree.adwin.renesas.com (unknown [172.29.43.62]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id DB65B4022BED; Tue, 11 Dec 2018 00:36:59 +0900 (JST) From: Biju Das To: Srinivas Kandagatla Cc: Biju Das , Simon Horman , Geert Uytterhoeven , Chris Paterson , Alexandre Belloni , Alessandro Zummo , Fabrizio Castro , linux-rtc@vger.kernel.org, linux-renesas-soc@vger.kernel.org Subject: [PATCH v2] nvmem: check invalid number of bytes in nvmem_{read,write}() Date: Mon, 10 Dec 2018 15:28:21 +0000 Message-Id: <1544455701-5720-1-git-send-email-biju.das@bp.renesas.com> X-Mailer: git-send-email 2.7.4 Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add check in nvmem_{read,write}()to ensure that nvmem core never passes an invalid number of bytes. Signed-off-by: Biju Das --- V1-->V2 * Moved checks from bin_attr_nvmem_{read/write} into nvmem_reg_{read,write} * Removed checks from nvmem_devicenvmem_device_{read,write}()_{read,write} --- drivers/nvmem/core.c | 97 ++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index f7301bb..dfbc8ff 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -76,19 +76,60 @@ static struct lock_class_key eeprom_lock_key; static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, void *val, size_t bytes) { - if (nvmem->reg_read) - return nvmem->reg_read(nvmem->priv, offset, val, bytes); + int rc; + size_t new_bytes; + + /* Stop the user from reading */ + if ((offset >= nvmem->size) || (bytes == 0)) + return 0; + + if ((nvmem->reg_read == NULL) || (bytes < nvmem->word_size)) + return -EINVAL; + + if (unlikely(check_add_overflow(bytes, offset, &new_bytes))) + return -EOVERFLOW; - return -EINVAL; + if (new_bytes > nvmem->size) + bytes = nvmem->size - offset; + + bytes = round_down(bytes, nvmem->word_size); + rc = nvmem->reg_read(nvmem->priv, offset, val, bytes); + + if (rc) + return rc; + + return bytes; } static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, void *val, size_t bytes) { - if (nvmem->reg_write) - return nvmem->reg_write(nvmem->priv, offset, val, bytes); + int rc; + size_t new_bytes; + + /* Stop the user from writing */ + if (offset >= nvmem->size) + return -ENOSPC; + + if (bytes == 0) + return 0; + + if ((nvmem->reg_write == NULL) || (bytes < nvmem->word_size)) + return -EINVAL; + + if (unlikely(check_add_overflow(bytes, offset, &new_bytes))) + return -EOVERFLOW; + + if (new_bytes > nvmem->size) + bytes = nvmem->size - offset; + + bytes = round_down(bytes, nvmem->word_size); + rc = nvmem->reg_write(nvmem->priv, offset, val, bytes); + + if (rc) + return rc; - return -EINVAL; + return bytes; } static ssize_t type_show(struct device *dev, @@ -111,33 +152,13 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, char *buf, loff_t pos, size_t count) { struct device *dev; - struct nvmem_device *nvmem; - int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); - nvmem = to_nvmem_device(dev); - - /* Stop the user from reading */ - if (pos >= nvmem->size) - return 0; - - if (count < nvmem->word_size) - return -EINVAL; - - if (pos + count > nvmem->size) - count = nvmem->size - pos; - - count = round_down(count, nvmem->word_size); - - rc = nvmem_reg_read(nvmem, pos, buf, count); - - if (rc) - return rc; - return count; + return nvmem_reg_read(to_nvmem_device(dev), pos, buf, count); } static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, @@ -145,33 +166,13 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, char *buf, loff_t pos, size_t count) { struct device *dev; - struct nvmem_device *nvmem; - int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); - nvmem = to_nvmem_device(dev); - - /* Stop the user from writing */ - if (pos >= nvmem->size) - return -EFBIG; - - if (count < nvmem->word_size) - return -EINVAL; - - if (pos + count > nvmem->size) - count = nvmem->size - pos; - - count = round_down(count, nvmem->word_size); - - rc = nvmem_reg_write(nvmem, pos, buf, count); - - if (rc) - return rc; - return count; + return nvmem_reg_write(to_nvmem_device(dev), pos, buf, count); } /* default read/write permissions */