DF-0797 / fix.diff
diff --git a/sys/vfs/hammer/hammer_ondisk.c b/sys/vfs/hammer/hammer_ondisk.c --- a/sys/vfs/hammer/hammer_ondisk.c +++ b/sys/vfs/hammer/hammer_ondisk.c @@ -209,6 +209,22 @@ } volume->vol_no = ondisk->vol_no; volume->vol_flags = ondisk->vol_flags; + + /* + * Validate vol_no before it is used as an index into + * hmp->volume_map[] (hammer.h:hammer_volume_number_add). The + * on-disk vol_no is a raw int32 and is attacker-controlled when a + * crafted filesystem image is mounted; without this check a value + * outside [0, HAMMER_MAX_VOLUMES) drives + * __hammer_vol_index(vol_no)=vol_no>>6 past the 4-element + * volume_map[] array, an out-of-bounds heap write. (DF-0797) + */ + if (volume->vol_no < 0 || volume->vol_no >= HAMMER_MAX_VOLUMES) { + hkprintf("volume %s has invalid vol_no %d\n", + volume->vol_name, volume->vol_no); + error = EFTYPE; + goto late_failure; + } volume->maxbuf_off = HAMMER_ENCODE_RAW_BUFFER(volume->vol_no, HAMMER_VOL_BUF_SIZE(ondisk)); diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h --- a/sys/vfs/hammer/hammer.h +++ b/sys/vfs/hammer/hammer.h @@ -1567,7 +1567,14 @@ static __inline int __hammer_vol_index(int vol_no) { - return(vol_no >> 6); + /* + * Mask the index to the size of hammer_mount.volume_map[] (4 qwords, + * HAMMER_MAX_VOLUMES=256 -> 256>>6=4). vol_no is validated in + * hammer_install_volume() before the first use, but mask here too as + * defense in depth so a stray caller can never index past the array. + * (DF-0797) + */ + return((vol_no >> 6) & 0x3); } static __inline uint64_t |