From fa468025859f4d73ee74ece7f2f8c13ad6e5aa73 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 16 Mar 2023 17:27:49 -0400 Subject: [PATCH] Fix possible bad bit shift in dnode_next_offset_level() 031d7c2fe6afaa78943bd0a563b91fc84ace42d7 did not handle reverse iteration, such that the original issue theoretically could still occur. Note that contrary to the claim in the ZFS disk format specification that a maximum of 6 levels are possible, 9 levels are possible with recordsize=512 and and indirect block size of 16KB. In this unusual configuration, span will be 65. The maximum size of span at 70 can be reached at recordsize=16K and an indirect blocksize of 16KB. When we are at this indirection level and are traversing backward, the minimum value is start, but we cannot calculate that with 64-bit arithmetic, so we avoid the calculation and instead rely on the earlier statement that did `*offset = start;`. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Reported-by: Coverity (CID-1466214) Closes #14618 --- module/zfs/dnode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c index d334386e0a..367bfaa807 100644 --- a/module/zfs/dnode.c +++ b/module/zfs/dnode.c @@ -2597,8 +2597,9 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, if (inc < 0) { /* traversing backwards; position offset at the end */ - ASSERT3U(*offset, <=, start); - *offset = MIN(*offset + (1ULL << span) - 1, start); + if (span < 8 * sizeof (*offset)) + *offset = MIN(*offset + (1ULL << span) - 1, + start); } else if (*offset < start) { *offset = start; }