⬢ DragonFlyBSD Kernel Audit
DF-3179 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/tmpfs/tmpfs_vfsops.c
+++ b/sys/vfs/tmpfs/tmpfs_vfsops.c
@@ -203,8 +203,19 @@
 			sizeof(struct tmpfs_dirent));
 	kmalloc_create(&tmp->tm_name_zone, "tmpfs name zone");
 
+	/*
+	 * Scale all tmpfs zone limits with the node budget so ordinary
+	 * operation cannot collide with the malloc default limit (kmem/10),
+	 * which PANICs for allocations made without M_NULLOK (e.g.
+	 * tmpfs_alloc_dirent).  Dirents are bounded by nodes_max*LINK_MAX
+	 * (hardlinks) and names by nodes_max*NAME_MAX in the worst case.
+	 */
 	kmalloc_obj_raise_limit(tmp->tm_node_zone,
 				sizeof(struct tmpfs_node) * tmp->tm_nodes_max);
+	kmalloc_obj_raise_limit(tmp->tm_dirent_zone,
+				sizeof(struct tmpfs_dirent) * tmp->tm_nodes_max);
+	kmalloc_raise_limit(tmp->tm_name_zone,
+			    (size_t)tmp->tm_nodes_max * (PATH_MAX / 2));
 
 	tmp->tm_ino = TMPFS_ROOTINO;
 
--- a/sys/vfs/tmpfs/tmpfs_subr.c
+++ b/sys/vfs/tmpfs/tmpfs_subr.c
@@ -304,7 +304,9 @@
 	struct tmpfs_dirent *nde;
 
 	nde = kmalloc_obj(sizeof(struct tmpfs_dirent),
-			  tmp->tm_dirent_zone, M_WAITOK);
+			  tmp->tm_dirent_zone, M_WAITOK | M_NULLOK);
+	if (nde == NULL)
+		return (ENOSPC);
 	nde->td_name = kmalloc(len + 1, tmp->tm_name_zone, M_WAITOK | M_NULLOK);
 	if (nde->td_name == NULL) {
 		kfree_obj(nde, tmp->tm_dirent_zone);