Created
January 6, 2013 20:24
-
-
Save jclulow/4469970 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| The following diff prevents us from overrunning the buffer and corrupting the heap: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/usr/src/uts/common/fs/zfs/dbuf.c b/usr/src/uts/common/fs/zfs/dbuf.c | |
| index 16e42b9..8a29851 100644 | |
| --- a/usr/src/uts/common/fs/zfs/dbuf.c | |
| +++ b/usr/src/uts/common/fs/zfs/dbuf.c | |
| @@ -510,51 +510,52 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags) | |
| { | |
| dnode_t *dn; | |
| spa_t *spa; | |
| zbookmark_t zb; | |
| uint32_t aflags = ARC_NOWAIT; | |
| arc_buf_t *pbuf; | |
| DB_DNODE_ENTER(db); | |
| dn = DB_DNODE(db); | |
| ASSERT(!refcount_is_zero(&db->db_holds)); | |
| /* We need the struct_rwlock to prevent db_blkptr from changing. */ | |
| ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock)); | |
| ASSERT(MUTEX_HELD(&db->db_mtx)); | |
| ASSERT(db->db_state == DB_UNCACHED); | |
| ASSERT(db->db_buf == NULL); | |
| if (db->db_blkid == DMU_BONUS_BLKID) { | |
| int bonuslen = MIN(dn->dn_bonuslen, dn->dn_phys->dn_bonuslen); | |
| ASSERT3U(bonuslen, <=, db->db.db_size); | |
| db->db.db_data = zio_buf_alloc(DN_MAX_BONUSLEN); | |
| arc_space_consume(DN_MAX_BONUSLEN, ARC_SPACE_OTHER); | |
| if (bonuslen < DN_MAX_BONUSLEN) | |
| bzero(db->db.db_data, DN_MAX_BONUSLEN); | |
| if (bonuslen) | |
| - bcopy(DN_BONUS(dn->dn_phys), db->db.db_data, bonuslen); | |
| + bcopy(DN_BONUS(dn->dn_phys), db->db.db_data, | |
| + MIN(bonuslen, DN_MAX_BONUSLEN)); | |
| DB_DNODE_EXIT(db); | |
| dbuf_update_data(db); | |
| db->db_state = DB_CACHED; | |
| mutex_exit(&db->db_mtx); | |
| return; | |
| } | |
| /* | |
| * Recheck BP_IS_HOLE() after dnode_block_freed() in case dnode_sync() | |
| * processes the delete record and clears the bp while we are waiting | |
| * for the dn_mtx (resulting in a "no" from block_freed). | |
| */ | |
| if (db->db_blkptr == NULL || BP_IS_HOLE(db->db_blkptr) || | |
| (db->db_level == 0 && (dnode_block_freed(dn, db->db_blkid) || | |
| BP_IS_HOLE(db->db_blkptr)))) { | |
| arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db); | |
| dbuf_set_data(db, arc_buf_alloc(dn->dn_objset->os_spa, | |
| db->db.db_size, db, type)); | |
| DB_DNODE_EXIT(db); | |
| bzero(db->db.db_data, db->db.db_size); | |
| db->db_state = DB_CACHED; | |
| *flags |= DB_RF_CACHED; | |
| mutex_exit(&db->db_mtx); | |
| return; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| This diff represents how far back in the call chain we'd have to go to be able to | |
| return EIO... and is probably not worth it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c | |
| index 743f5c4..aaf084e 100644 | |
| --- a/usr/src/uts/common/fs/zfs/dmu.c | |
| +++ b/usr/src/uts/common/fs/zfs/dmu.c | |
| @@ -216,50 +216,58 @@ dmu_rm_spill(objset_t *os, uint64_t object, dmu_tx_t *tx) | |
| rw_enter(&dn->dn_struct_rwlock, RW_WRITER); | |
| dnode_rm_spill(dn, tx); | |
| rw_exit(&dn->dn_struct_rwlock); | |
| dnode_rele(dn, FTAG); | |
| return (error); | |
| } | |
| /* | |
| * returns ENOENT, EIO, or 0. | |
| */ | |
| int | |
| dmu_bonus_hold(objset_t *os, uint64_t object, void *tag, dmu_buf_t **dbp) | |
| { | |
| dnode_t *dn; | |
| dmu_buf_impl_t *db; | |
| int error; | |
| error = dnode_hold(os, object, FTAG, &dn); | |
| if (error) | |
| return (error); | |
| rw_enter(&dn->dn_struct_rwlock, RW_READER); | |
| if (dn->dn_bonus == NULL) { | |
| rw_exit(&dn->dn_struct_rwlock); | |
| rw_enter(&dn->dn_struct_rwlock, RW_WRITER); | |
| + | |
| + if (dn->dn_bonuslen > DN_MAX_BONUSLEN || | |
| + dn->dn_phys->dn_bonuslen > DN_MAX_BONUSLEN) { | |
| + rw_exit(&dn->dn_struct_rwlock); | |
| + dnode_rele(dn, FTAG); | |
| + return (EIO); | |
| + } | |
| + | |
| if (dn->dn_bonus == NULL) | |
| dbuf_create_bonus(dn); | |
| } | |
| db = dn->dn_bonus; | |
| /* as long as the bonus buf is held, the dnode will be held */ | |
| if (refcount_add(&db->db_holds, tag) == 1) { | |
| VERIFY(dnode_add_ref(dn, db)); | |
| (void) atomic_inc_32_nv(&dn->dn_dbufs_count); | |
| } | |
| /* | |
| * Wait to drop dn_struct_rwlock until after adding the bonus dbuf's | |
| * hold and incrementing the dbuf count to ensure that dnode_move() sees | |
| * a dnode hold for every dbuf. | |
| */ | |
| rw_exit(&dn->dn_struct_rwlock); | |
| dnode_rele(dn, FTAG); | |
| VERIFY(0 == dbuf_read(db, NULL, DB_RF_MUST_SUCCEED | DB_RF_NOPREFETCH)); | |
| *dbp = &db->db; | |
| return (0); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment