DF-3054 / fix.diff
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, |