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 <boris.brezillon@free-electrons.com> Cc: Peter Pan <peterpandong@micron.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
9a5941080e
commit
5cdd929da5
@ -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)
|
|||||||
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);
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user