aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2017-06-27 15:22:21 -0400
committerRichard Weinberger <richard@nod.at>2017-11-13 15:39:19 -0500
commit5cdd929da53dd7347ec86afd94c3b840909c461e (patch)
tree6ea643c6246ad11ac23e921655a47499b4cd6dac
parent9a5941080ef29f1a0347ac2766e4d93312123b21 (diff)
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>
-rw-r--r--drivers/mtd/mtdcore.c44
1 files changed, 44 insertions, 0 deletions
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,
1100} 1100}
1101EXPORT_SYMBOL_GPL(mtd_panic_write); 1101EXPORT_SYMBOL_GPL(mtd_panic_write);
1102 1102
1103static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
1104 struct mtd_oob_ops *ops)
1105{
1106 /*
1107 * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving
1108 * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in
1109 * this case.
1110 */
1111 if (!ops->datbuf)
1112 ops->len = 0;
1113
1114 if (!ops->oobbuf)
1115 ops->ooblen = 0;
1116
1117 if (offs < 0 || offs + ops->len >= mtd->size)
1118 return -EINVAL;
1119
1120 if (ops->ooblen) {
1121 u64 maxooblen;
1122
1123 if (ops->ooboffs >= mtd_oobavail(mtd, ops))
1124 return -EINVAL;
1125
1126 maxooblen = ((mtd_div_by_ws(mtd->size, mtd) -
1127 mtd_div_by_ws(offs, mtd)) *
1128 mtd_oobavail(mtd, ops)) - ops->ooboffs;
1129 if (ops->ooblen > maxooblen)
1130 return -EINVAL;
1131 }
1132
1133 return 0;
1134}
1135
1103int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) 1136int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
1104{ 1137{
1105 int ret_code; 1138 int ret_code;
@@ -1107,6 +1140,10 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
1107 if (!mtd->_read_oob) 1140 if (!mtd->_read_oob)
1108 return -EOPNOTSUPP; 1141 return -EOPNOTSUPP;
1109 1142
1143 ret_code = mtd_check_oob_ops(mtd, from, ops);
1144 if (ret_code)
1145 return ret_code;
1146
1110 ledtrig_mtd_activity(); 1147 ledtrig_mtd_activity();
1111 /* 1148 /*
1112 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics 1149 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
@@ -1126,11 +1163,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
1126int mtd_write_oob(struct mtd_info *mtd, loff_t to, 1163int mtd_write_oob(struct mtd_info *mtd, loff_t to,
1127 struct mtd_oob_ops *ops) 1164 struct mtd_oob_ops *ops)
1128{ 1165{
1166 int ret;
1167
1129 ops->retlen = ops->oobretlen = 0; 1168 ops->retlen = ops->oobretlen = 0;
1130 if (!mtd->_write_oob) 1169 if (!mtd->_write_oob)
1131 return -EOPNOTSUPP; 1170 return -EOPNOTSUPP;
1132 if (!(mtd->flags & MTD_WRITEABLE)) 1171 if (!(mtd->flags & MTD_WRITEABLE))
1133 return -EROFS; 1172 return -EROFS;
1173
1174 ret = mtd_check_oob_ops(mtd, to, ops);
1175 if (ret)
1176 return ret;
1177
1134 ledtrig_mtd_activity(); 1178 ledtrig_mtd_activity();
1135 return mtd->_write_oob(mtd, to, ops); 1179 return mtd->_write_oob(mtd, to, ops);
1136} 1180}