diff --git a/sys/vfs/hpfs/hpfs_alsubr.c b/sys/vfs/hpfs/hpfs_alsubr.c index 8f1722d..7ffdbe9 100644 --- a/sys/vfs/hpfs/hpfs_alsubr.c +++ b/sys/vfs/hpfs/hpfs_alsubr.c @@ -57,6 +57,24 @@ alnode_t *); /* + * Maximum legitimate ab_busycnt for the in-kernel containers, computed from + * the on-disk data-area sizes (sys/vfs/hpfs/hpfs_alsubr.c includes hpfs.h): + * fnode fn_abd[0x60] = 96 bytes + * alsec as_abd[0x1E0] = 480 bytes + * alleaf_t = 12 bytes, alnode_t = 8 bytes (hpfs.h). + * + * ab_busycnt is taken straight from the on-disk alblk_t and is untrusted; + * these caps prevent the iteration loops in hpfs_hpbmap from walking past + * the data area into neighbouring heap memory (DF-0857). + */ +#define HPFS_FN_ABD_SIZE 0x60 +#define HPFS_AS_ABD_SIZE 0x1E0 +#define HPFS_FN_MAX_LEAF (HPFS_FN_ABD_SIZE / sizeof(alleaf_t)) /* 8 */ +#define HPFS_FN_MAX_NODE (HPFS_FN_ABD_SIZE / sizeof(alnode_t)) /* 12 */ +#define HPFS_AS_MAX_LEAF (HPFS_AS_ABD_SIZE / sizeof(alleaf_t)) /* 40 */ +#define HPFS_AS_MAX_NODE (HPFS_AS_ABD_SIZE / sizeof(alnode_t)) /* 60 */ + +/* * Map file offset to disk offset. hpfsnode have to be locked. */ int @@ -66,7 +84,7 @@ alblk_t * abp; alleaf_t *alp; alnode_t *anp; - int error, i; + int error, i, in_fnode; dprintf(("hpfs_hpbmap(0x%x, 0x%x): ",hp->h_no, bn)); @@ -74,8 +92,21 @@ abp = &hp->h_fn.fn_ab; alp = (alleaf_t *)&hp->h_fn.fn_abd; anp = (alnode_t *)&hp->h_fn.fn_abd; + in_fnode = 1; dive: + { + u_int maxcnt = (abp->ab_flag & AB_NODES) ? + (in_fnode ? HPFS_FN_MAX_NODE : HPFS_AS_MAX_NODE) : + (in_fnode ? HPFS_FN_MAX_LEAF : HPFS_AS_MAX_LEAF); + if (abp->ab_busycnt > maxcnt) { + kprintf("hpfs_hpbmap: forged ab_busycnt %u > max %u\n", + abp->ab_busycnt, maxcnt); + if (bp) + brelse(bp); + return (EINVAL); + } + } if (abp->ab_flag & AB_NODES) { for (i=0; iab_busycnt; i++, anp++) { dprintf(("[0x%x,0x%x] ",anp->an_nextoff,anp->an_lsn)); @@ -106,6 +137,7 @@ abp = &asp->as_ab; alp = (alleaf_t *)&asp->as_abd; anp = (alnode_t *)&asp->as_abd; + in_fnode = 0; goto dive; }