From owner-svn-src-all@FreeBSD.ORG Mon Nov 25 15:34:58 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id B5A35F6D; Mon, 25 Nov 2013 15:34:58 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 9514D221B; Mon, 25 Nov 2013 15:34:58 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rAPFYwJu096594; Mon, 25 Nov 2013 15:34:58 GMT (envelope-from gber@svn.freebsd.org) Received: (from gber@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rAPFYweo096592; Mon, 25 Nov 2013 15:34:58 GMT (envelope-from gber@svn.freebsd.org) Message-Id: <201311251534.rAPFYweo096592@svn.freebsd.org> From: Grzegorz Bernacki Date: Mon, 25 Nov 2013 15:34:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r258554 - stable/10/sys/dev/nand X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 25 Nov 2013 15:34:58 -0000 Author: gber Date: Mon Nov 25 15:34:57 2013 New Revision: 258554 URL: http://svnweb.freebsd.org/changeset/base/258554 Log: MFC: r258387,r258425 Split raw reading/programming into smaller chunks to avoid allocating too big chunk of kernel memory. Validate size of data. Add error handling to avoid calling copyout() when data has not been read correctly. Also MFC of change r258425 which fixes problem introduced by r258387. Reviewed by: zbb Reported by: x90c Approved by: re Modified: stable/10/sys/dev/nand/nand_cdev.c stable/10/sys/dev/nand/nand_geom.c Directory Properties: stable/10/sys/ (props changed) Modified: stable/10/sys/dev/nand/nand_cdev.c ============================================================================== --- stable/10/sys/dev/nand/nand_cdev.c Mon Nov 25 15:01:59 2013 (r258553) +++ stable/10/sys/dev/nand/nand_cdev.c Mon Nov 25 15:34:57 2013 (r258554) @@ -294,19 +294,40 @@ nand_ioctl(struct cdev *dev, u_long cmd, struct thread *td) { struct nand_chip *chip; + struct chip_geom *cg; struct nand_oob_rw *oob_rw = NULL; struct nand_raw_rw *raw_rw = NULL; device_t nandbus; + size_t bufsize = 0, len = 0; + size_t raw_size; + off_t off; uint8_t *buf = NULL; int ret = 0; uint8_t status; chip = (struct nand_chip *)dev->si_drv1; + cg = &chip->chip_geom; nandbus = device_get_parent(chip->dev); if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { raw_rw = (struct nand_raw_rw *)data; - buf = malloc(raw_rw->len, M_NAND, M_WAITOK); + raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); + + /* Check if len is not bigger than chip size */ + if (raw_rw->len > raw_size) + return (EFBIG); + + /* + * Do not ask for too much memory, in case of large transfers + * read/write in 16-pages chunks + */ + bufsize = 16 * (cg->page_size + cg->oob_size); + if (raw_rw->len < bufsize) + bufsize = raw_rw->len; + + buf = malloc(bufsize, M_NAND, M_WAITOK); + len = raw_rw->len; + off = 0; } switch(cmd) { case NAND_IO_ERASE: @@ -335,19 +356,37 @@ nand_ioctl(struct cdev *dev, u_long cmd, break; case NAND_IO_RAW_PROG: - ret = copyin(raw_rw->data, buf, raw_rw->len); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off, buf, - raw_rw->len); + while (len > 0) { + if (len < bufsize) + bufsize = len; + ret = copyin(raw_rw->data + off, buf, bufsize); + if (ret) + break; + ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, + bufsize); + if (ret) + break; + len -= bufsize; + off += bufsize; + } break; case NAND_IO_RAW_READ: - ret = nand_read_pages_raw(chip, raw_rw->off, buf, - raw_rw->len); - if (ret) - break; - ret = copyout(buf, raw_rw->data, raw_rw->len); + while (len > 0) { + if (len < bufsize) + bufsize = len; + + ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, + bufsize); + if (ret) + break; + + ret = copyout(buf, raw_rw->data + off, bufsize); + if (ret) + break; + len -= bufsize; + off += bufsize; + } break; case NAND_IO_PAGE_STAT: Modified: stable/10/sys/dev/nand/nand_geom.c ============================================================================== --- stable/10/sys/dev/nand/nand_geom.c Mon Nov 25 15:01:59 2013 (r258553) +++ stable/10/sys/dev/nand/nand_geom.c Mon Nov 25 15:34:57 2013 (r258554) @@ -193,20 +193,42 @@ nand_ioctl(struct disk *ndisk, u_long cm struct thread *td) { struct nand_chip *chip; + struct chip_geom *cg; struct nand_oob_rw *oob_rw = NULL; struct nand_raw_rw *raw_rw = NULL; device_t nandbus; + size_t bufsize = 0, len = 0; + size_t raw_size; + off_t off; uint8_t *buf = NULL; int ret = 0; uint8_t status; chip = (struct nand_chip *)ndisk->d_drv1; + cg = &chip->chip_geom; nandbus = device_get_parent(chip->dev); if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { raw_rw = (struct nand_raw_rw *)data; - buf = malloc(raw_rw->len, M_NAND, M_WAITOK); + raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); + + /* Check if len is not bigger than chip size */ + if (raw_rw->len > raw_size) + return (EFBIG); + + /* + * Do not ask for too much memory, in case of large transfers + * read/write in 16-pages chunks + */ + bufsize = 16 * (cg->page_size + cg->oob_size); + if (raw_rw->len < bufsize) + bufsize = raw_rw->len; + + buf = malloc(bufsize, M_NAND, M_WAITOK); + len = raw_rw->len; + off = 0; } + switch (cmd) { case NAND_IO_ERASE: ret = nand_erase_blocks(chip, ((off_t *)data)[0], @@ -234,15 +256,38 @@ nand_ioctl(struct disk *ndisk, u_long cm break; case NAND_IO_RAW_PROG: - copyin(raw_rw->data, buf, raw_rw->len); - ret = nand_prog_pages_raw(chip, raw_rw->off, buf, - raw_rw->len); + while (len > 0) { + if (len < bufsize) + bufsize = len; + + ret = copyin(raw_rw->data + off, buf, bufsize); + if (ret) + break; + ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, + bufsize); + if (ret) + break; + len -= bufsize; + off += bufsize; + } break; case NAND_IO_RAW_READ: - ret = nand_read_pages_raw(chip, raw_rw->off, buf, - raw_rw->len); - copyout(buf, raw_rw->data, raw_rw->len); + while (len > 0) { + if (len < bufsize) + bufsize = len; + + ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, + bufsize); + if (ret) + break; + + ret = copyout(buf, raw_rw->data + off, bufsize); + if (ret) + break; + len -= bufsize; + off += bufsize; + } break; case NAND_IO_GET_CHIP_PARAM: