diff --git a/sys/vfs/ntfs/ntfs_subr.c b/sys/vfs/ntfs/ntfs_subr.c --- a/sys/vfs/ntfs/ntfs_subr.c +++ b/sys/vfs/ntfs/ntfs_subr.c @@ -194,6 +194,25 @@ nextaalp = NULL; for(; len > 0; aalp = nextaalp) { + /* DF-0790: validate the entry before dereferencing any field + * or advancing the walk. A crafted $ATTRIBUTE_LIST can have + * reclen == 0 (infinite loop, since len never decreases and + * NTFS_NEXTREC returns the same pointer) or reclen > len + * (size_t underflow on `len -= reclen`, then the next + * iteration dereferences nextaalp == NULL -> panic). + * Require the fixed entry header to fit in the remaining + * buffer and reclen to be sane. The minimum entry size is + * the fixed header without the variable name tail + * (al_name[1] is a flexible-array placeholder). */ + if (len < sizeof(struct attr_attrlist) - sizeof(u_int16_t) || + aalp->reclen < sizeof(struct attr_attrlist) - sizeof(u_int16_t) || + aalp->reclen > len) { + error = EINVAL; + kprintf("ntfs_ntvattrget: malformed attrlist entry " + "(reclen %u, len %zu)\n", aalp->reclen, len); + goto out; + } + dprintf(("ntfs_ntvattrget: " \ "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \ aalp->al_inumber, aalp->al_type, \