libnvdimm/labels: Bound the on-media label size before the shift

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: 564e871aa6 ("libnvdimm, label: add v1.2 nvdimm label definitions")
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20260624-b4-disp-d8279485-v3-2-cdb6cab28b41@proton.me
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
This commit is contained in:
Bryam Vargas 2026-06-24 01:03:46 -05:00 committed by Alison Schofield
parent 0377706861
commit 18f9124248

View File

@ -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",