提交 5cdd929d 编写于 作者: B Boris Brezillon 提交者: Richard Weinberger

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: NBoris Brezillon <boris.brezillon@free-electrons.com>
Cc: Peter Pan <peterpandong@micron.com>
Signed-off-by: NRichard Weinberger <richard@nod.at>
上级 9a594108
...@@ -1100,6 +1100,39 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, ...@@ -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); 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 mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
{ {
int ret_code; int ret_code;
...@@ -1107,6 +1140,10 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ...@@ -1107,6 +1140,10 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
if (!mtd->_read_oob) if (!mtd->_read_oob)
return -EOPNOTSUPP; return -EOPNOTSUPP;
ret_code = mtd_check_oob_ops(mtd, from, ops);
if (ret_code)
return ret_code;
ledtrig_mtd_activity(); ledtrig_mtd_activity();
/* /*
* In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
...@@ -1126,11 +1163,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob); ...@@ -1126,11 +1163,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
int mtd_write_oob(struct mtd_info *mtd, loff_t to, int mtd_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
int ret;
ops->retlen = ops->oobretlen = 0; ops->retlen = ops->oobretlen = 0;
if (!mtd->_write_oob) if (!mtd->_write_oob)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!(mtd->flags & MTD_WRITEABLE)) if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS; return -EROFS;
ret = mtd_check_oob_ops(mtd, to, ops);
if (ret)
return ret;
ledtrig_mtd_activity(); ledtrig_mtd_activity();
return mtd->_write_oob(mtd, to, ops); return mtd->_write_oob(mtd, to, ops);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册