DragonFlyBSD Kernel Audit
DF-0787 / fix.diff
← back to finding ↓ download raw
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
@@ -302,21 +302,49 @@
 	}
 
 	dprintf(("ntfs_loadntnode: load attrs for ino: %"PRId64"\n",ip->i_number));
-	off = mfrp->fr_attroff;
-	ap = (struct attr *) ((caddr_t)mfrp + off);
+	{
+		size_t recsz = ntfs_bntob(ntmp->ntm_bpmftrec);
 
-	LIST_INIT(&ip->i_valist);
+		off = mfrp->fr_attroff;
+		/* DF-0787: bound the attribute walk by the MFT record size and
+		 * reject malformed entries (zero/huge reclen, overflowed offset)
+		 * before dereferencing the next attribute header. Without this,
+		 * a crafted MFT record causes ntfs_loadntnode() to loop forever,
+		 * leaking struct ntvattr allocations until the slab allocator
+		 * panics with "malloc limit exceeded". */
+		if (off < sizeof(struct filerec) || off >= (int)recsz) {
+			error = EINVAL;
+			kprintf("ntfs_loadntnode: bad attribute offset %d for "
+			       "ino %"PRId64"\n", off, ip->i_number);
+			goto out;
+		}
+		ap = (struct attr *) ((caddr_t)mfrp + off);
 
-	while (ap->a_hdr.a_type != -1) {
-		error = ntfs_attrtontvattr(ntmp, &nvap, ap);
-		if (error)
-			break;
-		nvap->va_ip = ip;
+		LIST_INIT(&ip->i_valist);
 
-		LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
+		while (ap->a_hdr.a_type != -1) {
+			/* The attribute header must fit in the remaining record bytes. */
+			if ((size_t)off + sizeof(struct attrhdr) > recsz) {
+				error = EINVAL;
+				break;
+			}
+			/* reclen must be sane: at least the header, and not past the end. */
+			if (ap->a_hdr.reclen < sizeof(struct attrhdr) ||
+			    ap->a_hdr.reclen > recsz - off) {
+				error = EINVAL;
+				break;
+			}
 
-		off += ap->a_hdr.reclen;
-		ap = (struct attr *) ((caddr_t)mfrp + off);
+			error = ntfs_attrtontvattr(ntmp, &nvap, ap);
+			if (error)
+				break;
+			nvap->va_ip = ip;
+
+			LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
+
+			off += ap->a_hdr.reclen;
+			ap = (struct attr *) ((caddr_t)mfrp + off);
+		}
 	}
 	if (error) {
 		kprintf("ntfs_loadntnode: failed to load attr ino: %"PRId64"\n",