DragonFlyBSD Kernel Audit
DF-3054 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/dirfs/dirfs_vnops.c b/sys/vfs/dirfs/dirfs_vnops.c
index a9acfbb5..61a8c1ab 100644
--- a/sys/vfs/dirfs/dirfs_vnops.c
+++ b/sys/vfs/dirfs/dirfs_vnops.c
@@ -387,6 +387,11 @@ dirfs_getattr(struct vop_getattr_args *ap)
 
 	if (!dirfs_node_isroot(dnp)) {
 		pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
+		if (pathnp == NULL) {
+			/* relative path > MAXPATHLEN from any open fd */
+			error = ENAMETOOLONG;
+			goto out;
+		}
 
 		KKASSERT(pathnp->dn_fd != DIRFS_NOFD);
 
@@ -395,6 +400,7 @@ dirfs_getattr(struct vop_getattr_args *ap)
 	} else {
 		error = dirfs_node_stat(DIRFS_NOFD, dmp->dm_path, dnp);
 	}
+out:
 
 	if (error == 0) {
 		dirfs_node_lock(dnp);
@@ -1324,6 +1330,11 @@ dirfs_readlink(struct vop_readlink_args *ap)
 	lwkt_gettoken(&mp->mnt_token);
 
 	pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
+	if (pathnp == NULL) {
+		/* relative path > MAXPATHLEN from any open fd */
+		lwkt_reltoken(&mp->mnt_token);
+		return (ENAMETOOLONG);
+	}
 
 	buf = kmalloc(uio->uio_resid, M_DIRFS_MISC, M_WAITOK | M_ZERO);
 	nlen = readlinkat(pathnp->dn_fd, dnp->dn_name, buf, uio->uio_resid);
diff --git a/sys/vfs/dirfs/dirfs_subr.c b/sys/vfs/dirfs/dirfs_subr.c
index 0fda4856..3c0af31c 100644
--- a/sys/vfs/dirfs/dirfs_subr.c
+++ b/sys/vfs/dirfs/dirfs_subr.c
@@ -189,6 +189,15 @@ dirfs_alloc_file(dirfs_mount_t dmp, dirfs_node_t *dnpp, dirfs_node_t pdnp,
 	dirfs_node_unlock(dnp);
 
 	pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
+	if (pathnp == NULL) {
+		/*
+		 * Relative path longer than MAXPATHLEN from the closest
+		 * fd-holding ancestor: never dereference the NULL return,
+		 * tear the fresh node down instead.
+		 */
+		dirfs_node_free(dmp, dnp);
+		return (ENAMETOOLONG);
+	}
 
 	if (openflags && vap != NULL) {
 		dnp->dn_fd = openat(pathnp->dn_fd, tmp,