aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2014-08-29 12:24:26 -0700
committerBrian Behlendorf <[email protected]>2014-09-08 09:15:38 -0700
commitceb49b0acd21ed44aa8e4d1464447eef071d3bab (patch)
tree960c200198e924c66c5fdc3f1a2d8560b1798a50
parentcd3939c5f06945a3883a362379d0c12e57f31a4d (diff)
Add object type checking to zap_lockdir()
If a non-ZAP object is passed to zap_lockdir() it will be treated as a valid ZAP object. This can result in zap_lockdir() attempting to read what it believes are leaf blocks from invalid disk locations. The SCSI layer will eventually generate errors for these bogus IOs but the caller will hang in zap_get_leaf_byblk(). The good news is that is a situation which can not occur unless the pool has been damaged. The bad news is that there are reports from both FreeBSD and Solaris of damaged pools. Specifically, there are normal files in the filesystem which reference another normal file as their parent. Since pools like this are known to exist the zap_lockdir() function has been updated to verify the type of the object. If a non-ZAP object has been passed it EINVAL will be returned immediately. Signed-off-by: Brian Behlendorf <[email protected]> Issue #2597 Issue #2602
-rw-r--r--module/zfs/zap_micro.c11
1 files changed, 4 insertions, 7 deletions
diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c
index 2249b7338..5d812bdd9 100644
--- a/module/zfs/zap_micro.c
+++ b/module/zfs/zap_micro.c
@@ -446,6 +446,7 @@ int
zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp)
{
+ dmu_object_info_t doi;
zap_t *zap;
dmu_buf_t *db;
krw_t lt;
@@ -457,13 +458,9 @@ zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
if (err)
return (err);
-#ifdef ZFS_DEBUG
- {
- dmu_object_info_t doi;
- dmu_object_info_from_db(db, &doi);
- ASSERT3U(DMU_OT_BYTESWAP(doi.doi_type), ==, DMU_BSWAP_ZAP);
- }
-#endif
+ dmu_object_info_from_db(db, &doi);
+ if (DMU_OT_BYTESWAP(doi.doi_type) != DMU_BSWAP_ZAP)
+ return (SET_ERROR(EINVAL));
zap = dmu_buf_get_user(db);
if (zap == NULL)