diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2017-06-27 15:22:21 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2017-11-13 15:39:19 -0500 |
commit | 5cdd929da53dd7347ec86afd94c3b840909c461e (patch) | |
tree | 6ea643c6246ad11ac23e921655a47499b4cd6dac | |
parent | 9a5941080ef29f1a0347ac2766e4d93312123b21 (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.c | 44 |
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 | } |
1101 | EXPORT_SYMBOL_GPL(mtd_panic_write); | 1101 | EXPORT_SYMBOL_GPL(mtd_panic_write); |
1102 | 1102 | ||
1103 | static 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 | |||
1103 | int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) | 1136 | int 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); | |||
1126 | int mtd_write_oob(struct mtd_info *mtd, loff_t to, | 1163 | int 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 | } |