__nd_label_validate() reads several index fields straight from the label
storage medium. This series fixes two of them.
Patch 1 (the original report): the bound multiplies the on-media nslot by the
label size in 32 bits, which wraps, so a crafted nslot passes the config_size
check and then drives an out-of-bounds memset in nd_label_data_init().
Evaluate the product in 64 bits. Tagged for stable.
Patch 2: the v1.2 label size is computed as 1 << (7 + labelsize), where
labelsize is a u8 from the medium; a value of 24 or more makes the shift
undefined. Reject labelsize > 1 before the shift.
v3: Drop the "cap nslot at 64K" patch from v2. A closer reading -- and the
Sashiko AI review -- showed it was wrong on both counts: the allocation in
nd_label_data_init() is kvzalloc(config_size), not nslot-derived, so the
cap shrinks nothing; and the kernel itself writes nslot =
nvdimm_num_label_slots() on init, which exceeds 64K once config_size is
above ~8.4MB, so the cap would reject a freshly-formatted large device on
the next probe -- a self-brick. Patch 1's exact 64-bit bound already
closes the overflow. Replaced it with the labelsize-shift fix the same
review surfaced.
v2:
https://lore.kernel.org/all/[email protected]/
v1:
https://lore.kernel.org/all/[email protected]/
Verified -m64 and -m32: patch 1's 64-bit bound agrees with an exact
divide-based check, and an out-of-tree module mirroring nd_label_data_init()
reproduces the KASAN slab-out-of-bounds write unpatched and is clean when
patched.
A boundary truth table confirms the self-brick the v2 cap would have caused
(kernel nslot > 64K for config_size > ~8.4MB) and that rejecting labelsize > 1
removes the undefined shift while keeping the two valid sizes. Harness
available on request.
A negative ndctl test (test/label-compat.sh) will follow separately, per
Alison's suggestion. With the nslot cap dropped it now covers two vectors
rather than one: an oversize nslot for patch 1 and an oversize labelsize for
patch 2.
Signed-off-by: Bryam Vargas <[email protected]>
---
Bryam Vargas (2):
libnvdimm/labels: Prevent integer overflow in __nd_label_validate()
libnvdimm/labels: Bound the on-media label size before the shift
drivers/nvdimm/label.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
---
base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
change-id: 20260624-b4-disp-d8279485-1b59fb6a7819
Best regards,
--
Bryam Vargas <[email protected]>