]> granicus.if.org Git - zfs/commitdiff
Some additional send stream validity checking
authorNed Bass <bass6@llnl.gov>
Wed, 26 Jul 2017 01:52:40 +0000 (18:52 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 26 Jul 2017 01:52:40 +0000 (18:52 -0700)
Check in the DMU whether an object record in a send stream being
received contains an unsupported dnode slot count, and return an
error if it does. Failure to catch an unsupported dnode slot count
would result in a panic when the SPA attempts to increment the
reference count for the large_dnode feature and the pool has the
feature disabled. This is not normally an issue for a well-formed
send stream which would have the DMU_BACKUP_FEATURE_LARGE_DNODE flag
set if it contains large dnodes, so it will be rejected as
unsupported if the required feature is disabled. This change adds a
missing object record field validation.

Add missing stream feature flag checks in
dmu_recv_resume_begin_check().

Consolidate repetitive comment blocks in dmu_recv_begin_check().

Update zstreamdump to print the dnode slot count (dn_slots) for an
object record when running in verbose mode.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Signed-off-by: Ned Bass <bass6@llnl.gov>
Closes #6396

cmd/zstreamdump/zstreamdump.c
module/zfs/dmu_send.c

index b2f7bfdff9f78df51bcaa8e6b115ccb465d96c6e..2fe95dfb6199a4ed10a75df9b8e9ff14dcf35b8d 100644 (file)
@@ -422,12 +422,14 @@ main(int argc, char *argv[])
                        }
                        if (verbose) {
                                (void) printf("OBJECT object = %llu type = %u "
-                                   "bonustype = %u blksz = %u bonuslen = %u\n",
+                                   "bonustype = %u blksz = %u bonuslen = %u "
+                                   "dn_slots = %u\n",
                                    (u_longlong_t)drro->drr_object,
                                    drro->drr_type,
                                    drro->drr_bonustype,
                                    drro->drr_blksz,
-                                   drro->drr_bonuslen);
+                                   drro->drr_bonuslen,
+                                   drro->drr_dn_slots);
                        }
                        if (drro->drr_bonuslen > 0) {
                                (void) ssread(buf,
index 7162355d45c866981ab0f5ccf03961a3b34c6db7..eb27b5e7174b27656066fadd29cae4fa4b018e95 100644 (file)
@@ -1428,17 +1428,12 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
        /*
         * The receiving code doesn't know how to translate large blocks
         * to smaller ones, so the pool must have the LARGE_BLOCKS
-        * feature enabled if the stream has LARGE_BLOCKS.
+        * feature enabled if the stream has LARGE_BLOCKS. Same with
+        * large dnodes.
         */
        if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
            !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
                return (SET_ERROR(ENOTSUP));
-
-       /*
-        * The receiving code doesn't know how to translate large dnodes
-        * to smaller ones, so the pool must have the LARGE_DNODE
-        * feature enabled if the stream has LARGE_DNODE.
-        */
        if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
            !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE))
                return (SET_ERROR(ENOTSUP));
@@ -1678,6 +1673,19 @@ dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx)
            !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
                return (SET_ERROR(ENOTSUP));
 
+       /*
+        * The receiving code doesn't know how to translate large blocks
+        * to smaller ones, so the pool must have the LARGE_BLOCKS
+        * feature enabled if the stream has LARGE_BLOCKS. Same with
+        * large dnodes.
+        */
+       if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
+               return (SET_ERROR(ENOTSUP));
+       if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE))
+               return (SET_ERROR(ENOTSUP));
+
        (void) snprintf(recvname, sizeof (recvname), "%s/%s",
            tofs, recv_clone_name);
 
@@ -2121,7 +2129,9 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
            drro->drr_blksz < SPA_MINBLOCKSIZE ||
            drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(rwa->os)) ||
            drro->drr_bonuslen >
-           DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os)))) {
+           DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os))) ||
+           drro->drr_dn_slots >
+           (spa_maxdnodesize(dmu_objset_spa(rwa->os)) >> DNODE_SHIFT))  {
                return (SET_ERROR(EINVAL));
        }