]> granicus.if.org Git - zfs/commitdiff
Avoid undefined shift overflow in fzap_cursor_retrieve()
authorGvozden Neskovic <neskovic@gmail.com>
Fri, 2 Sep 2016 13:10:34 +0000 (15:10 +0200)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 29 Sep 2016 22:55:41 +0000 (15:55 -0700)
Avoid calculating (1<<64) if lh_prefix_len == 0. Semantics of the method remain
the same.

Assert (lh_prefix_len > 0) in zap_expand_leaf() to detect possibly the same
problem.

Issue #4883

Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
module/zfs/zap.c

index 0ed6d7f49d50f29647ddef384b0f3b00e34db6e6..a8ccd2895501128c9caf368daa70fef1ac6bb626 100644 (file)
@@ -693,6 +693,8 @@ zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l,
                ASSERT0(err); /* we checked for i/o errors above */
        }
 
+       ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_prefix_len, >, 0);
+
        if (hash & (1ULL << (64 - zap_leaf_phys(l)->l_hdr.lh_prefix_len))) {
                /* we want the sibling */
                zap_put_leaf(l);
@@ -1230,17 +1232,23 @@ again:
        err = zap_leaf_lookup_closest(l, zc->zc_hash, zc->zc_cd, &zeh);
 
        if (err == ENOENT) {
-               uint64_t nocare =
-                   (1ULL << (64 - zap_leaf_phys(l)->l_hdr.lh_prefix_len)) - 1;
-               zc->zc_hash = (zc->zc_hash & ~nocare) + nocare + 1;
-               zc->zc_cd = 0;
-               if (zap_leaf_phys(l)->l_hdr.lh_prefix_len == 0 ||
-                   zc->zc_hash == 0) {
+               if (zap_leaf_phys(l)->l_hdr.lh_prefix_len == 0) {
                        zc->zc_hash = -1ULL;
+                       zc->zc_cd = 0;
                } else {
-                       zap_put_leaf(zc->zc_leaf);
-                       zc->zc_leaf = NULL;
-                       goto again;
+                       uint64_t nocare = (1ULL <<
+                           (64 - zap_leaf_phys(l)->l_hdr.lh_prefix_len)) - 1;
+
+                       zc->zc_hash = (zc->zc_hash & ~nocare) + nocare + 1;
+                       zc->zc_cd = 0;
+
+                       if (zc->zc_hash == 0) {
+                               zc->zc_hash = -1ULL;
+                       } else {
+                               zap_put_leaf(zc->zc_leaf);
+                               zc->zc_leaf = NULL;
+                               goto again;
+                       }
                }
        }