From 5cdd929da53dd7347ec86afd94c3b840909c461e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 27 Jun 2017 21:22:21 +0200 Subject: [PATCH] mtd: Add sanity checks in mtd_write/read_oob() Unlike what's done in mtd_read/write(), there are no checks to make sure the parameters passed to mtd_read/write_oob() are consistent, which forces implementers of ->_read/write_oob() to do it, which in turn leads to code duplication and possibly errors in the logic. Do general sanity checks, like ops fields consistency and range checking. Signed-off-by: Boris Brezillon Cc: Peter Pan Signed-off-by: Richard Weinberger --- drivers/mtd/mtdcore.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index ecb0380158f9..f80e911b8843 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1100,6 +1100,39 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, } EXPORT_SYMBOL_GPL(mtd_panic_write); +static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs, + struct mtd_oob_ops *ops) +{ + /* + * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving + * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in + * this case. + */ + if (!ops->datbuf) + ops->len = 0; + + if (!ops->oobbuf) + ops->ooblen = 0; + + if (offs < 0 || offs + ops->len >= mtd->size) + return -EINVAL; + + if (ops->ooblen) { + u64 maxooblen; + + if (ops->ooboffs >= mtd_oobavail(mtd, ops)) + return -EINVAL; + + maxooblen = ((mtd_div_by_ws(mtd->size, mtd) - + mtd_div_by_ws(offs, mtd)) * + mtd_oobavail(mtd, ops)) - ops->ooboffs; + if (ops->ooblen > maxooblen) + return -EINVAL; + } + + return 0; +} + int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { int ret_code; @@ -1107,6 +1140,10 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) if (!mtd->_read_oob) return -EOPNOTSUPP; + ret_code = mtd_check_oob_ops(mtd, from, ops); + if (ret_code) + return ret_code; + ledtrig_mtd_activity(); /* * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics @@ -1126,11 +1163,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob); int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { + int ret; + ops->retlen = ops->oobretlen = 0; if (!mtd->_write_oob) return -EOPNOTSUPP; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; + + ret = mtd_check_oob_ops(mtd, to, ops); + if (ret) + return ret; + ledtrig_mtd_activity(); return mtd->_write_oob(mtd, to, ops); } -- 2.11.0