From: Bryam Vargas <[email protected]>
For a v1.2+ index, __nd_label_validate() computes the label size as
1 << (7 + nsindex[i]->labelsize), where labelsize is a u8 read from
the label storage medium. A value of 25 or more makes the shift count
reach or exceed the width of int -- undefined behavior -- and 24 already
shifts into the sign bit. Only 0 (128-byte) and 1 (256-byte) are valid.
Reject a labelsize above 1 before the shift. The result was rejected by
the following size comparison anyway, so this only removes the undefined
shift on a crafted or corrupted medium; conforming labels are unaffected.
Fixes: 564e871aa66f ("libnvdimm, label: add v1.2 nvdimm label definitions")
Signed-off-by: Bryam Vargas <[email protected]>
---
drivers/nvdimm/label.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index ec12ce72cfe2..dea2eee86d13 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -145,10 +145,21 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd)
/* label sizes larger than 128 arrived with v1.2 */
version = __le16_to_cpu(nsindex[i]->major) * 100
+ __le16_to_cpu(nsindex[i]->minor);
- if (version >= 102)
+ if (version >= 102) {
+ /*
+ * labelsize feeds the shift below; only 0 (128-byte)
+ * and 1 (256-byte) are valid -- a larger value would
+ * overflow or exceed the width of int.
+ */
+ if (nsindex[i]->labelsize > 1) {
+ dev_dbg(dev, "nsindex%d labelsize: %d
invalid\n",
+ i, nsindex[i]->labelsize);
+ continue;
+ }
labelsize = 1 << (7 + nsindex[i]->labelsize);
- else
+ } else {
labelsize = 128;
+ }
if (labelsize != sizeof_namespace_label(ndd)) {
dev_dbg(dev, "nsindex%d labelsize %d invalid\n",
--
2.43.0